diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index b7b2258cf..70b439138 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1126,6 +1126,8 @@ Teleport around the level. Default key is '^T'. .lp #terrain Show bare map without displaying monsters, objects, or traps. Autocompletes. +.lp #therecmdmenu +Show a menu of possible actions in a location next to you. .lp #throw Throw something. Default key is 't'. .lp #timeout @@ -2559,8 +2561,9 @@ 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 herecmd_menu -When using a windowport that supports mouse and clicking on yourself, show -a menu of possible actions for this location. Same as herecmdmenu command. +When using a windowport that supports mouse and clicking on yourself or +next to you, show a menu of possible actions for the location. +Same as herecmdmenu and therecmdmenu commands. .lp hilite_pet Visually distinguish pets from similar animals (default off). The behavior of this option depends on the type of windowing you use. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 66610799e..6612ae19c 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -1186,6 +1186,9 @@ Show what type of thing a map symbol corresponds to. Default key is '{\tt ;}'. \item[\tb{\#help}] Show the help menu. Default key is '{\tt ?}', and '{\tt h}' if {\it number\verb+_+pad\/} is on. %.lp +\item[\tb{\#herecmdmenu}] +Show a menu of possible actions in your current location. +%.lp \item[\tb{\#history}] Show long version and game history. Default key is '{\tt V}'. %.lp @@ -1386,6 +1389,9 @@ Teleport around the level. Default key is '{\tt \^{}T}'. Show bare map without displaying monsters, objects, or traps. Autocompletes. %.lp +\item[\tb{\#therecmdmenu}] +Show a menu of possible actions in a location next to you. +%.lp \item[\tb{\#throw}] Throw something. Default key is '{\tt t}'. %.lp @@ -3125,8 +3131,9 @@ 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{herecmd\verb+_+menu}] -When using a windowport that supports mouse and clicking on yourself, show -a menu of possible actions for this location. Same as herecmdmenu command. +When using a windowport that supports mouse and clicking on yourself or +next to you, show a menu of possible actions for the location. +Same as herecmdmenu and therecmdmenu commands. %.lp \item[\ib{hilite\verb+_+pet}] Visually distinguish pets from similar animals (default off). diff --git a/doc/fixes36.1 b/doc/fixes36.1 index ff470d323..04d4f53a1 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -462,6 +462,15 @@ when poly'd into a giant and moving onto a boulder's spot, you could get "you it up", "you are carrying too much stuff to pick up another boulder" improve #adjust command's handling of the '$' and '#' inventory slots prevent #adjust from allowing anything to be moved into the special '-' slot +sometimes rings dropped into sinks can be found in the pipes +doors in special levels were always generated in vertical orientation +assigning a type name to a potion on the floor which is actually a mimic could + prompt "Call a stream of fluid:" (bogus 'fromsink') +with perm_invent option enabled and no inventory, 'i' put up an empty menu +charisma affects the leeway in demon lord bribes +make Vlad slightly tougher +reduce the amount of gold laying on the floor +locked chests and large boxes contain more stuff Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository @@ -521,6 +530,7 @@ hero poly'd into vampire could drain monster down to 0 HP without killing it, fix mention_walls reporting secret doors as solid stone jumping over water unintentionally moved hero through that water, causing drowning if not able to water walk or fly +try again to fix achievement recording bug with mines and sokoban prizes Platform- and/or Interface-Specific Fixes @@ -583,6 +593,9 @@ X11/USE_XPM: [post-3.6.0 issue] the 'tiles' bug of incorrect total_tiles_used for STATUES_LOOK_LIKE_MONSTERS broke XPM manipulation of tiles data PANICTRACE: PANICTRACE_GDB used wrong value for ARGV0 when launching gdb if 'nethack -dpath' was used to specify non-default playground directory +win32gui: gather raw_print error messages into a single dialog window +win32tty: fix display errors when using a font with double wide or ambiguous + width characters General New Features @@ -720,6 +733,7 @@ X11: more terminal-like default resources win32gui: save and load map colors from registry X11: add new character selection dialog, and obey player_selection:dialog unix: reduce makefile verbosity by default +win32gui: new player selection dialog NetHack Community Patches (or Variation) Included diff --git a/include/artifact.h b/include/artifact.h index 4b7f55d6d..32261fdfd 100644 --- a/include/artifact.h +++ b/include/artifact.h @@ -56,14 +56,16 @@ struct artifact { }; /* 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) +enum invoke_prop_types { + TAMING = (LAST_PROP + 1), + HEALING, + ENERGY_BOOST, + UNTRAP, + CHARGE_OBJ, + LEV_TELE, + CREATE_PORTAL, + ENLIGHTENING, + CREATE_AMMO +}; #endif /* ARTIFACT_H */ diff --git a/include/extern.h b/include/extern.h index 1be0255d7..07c714ac0 100644 --- a/include/extern.h +++ b/include/extern.h @@ -924,6 +924,11 @@ E int NDECL(phase_of_the_moon); E boolean NDECL(friday_13th); E int NDECL(night); E int NDECL(midnight); +E void FDECL(strbuf_init, (strbuf_t *)); +E void FDECL(strbuf_append, (strbuf_t *, const char *)); +E void FDECL(strbuf_reserve, (strbuf_t *, int)); +E void FDECL(strbuf_empty, (strbuf_t *)); +E void FDECL(strbuf_nl_to_crlf, (strbuf_t *)); /* ### invent.c ### */ diff --git a/include/flag.h b/include/flag.h index 5b205e5b7..81630bd27 100644 --- a/include/flag.h +++ b/include/flag.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 flag.h $NHDT-Date: 1505214875 2017/09/12 11:14:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.123 $ */ +/* NetHack 3.6 flag.h $NHDT-Date: 1508827590 2017/10/24 06:46:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.129 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -191,6 +191,7 @@ struct instance_flags { * behaviour of various NetHack functions and probably warrant * a structure of their own elsewhere some day. */ + boolean defer_plname; /* X11 hack: askname() might not set plname */ boolean herecmd_menu; /* use menu when mouseclick on yourself */ boolean invis_goldsym; /* gold symbol is ' '? */ int parse_config_file_src; /* hack for parse_config_line() */ @@ -349,25 +350,24 @@ struct instance_flags { 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_scroll_margin; /* scroll map when this far from the edge */ int wc_map_mode; /* specify map viewing options, mostly - for backward compatibility */ + * 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 */ + * 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 wc2_hitpointbar; /* show graphical bar representing hit points */ - 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 */ + boolean wc2_darkgray; /* try to use dark-gray color for black glyphs */ + boolean wc2_hitpointbar; /* show graphical bar representing hit points */ + 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 @@ -381,6 +381,11 @@ struct instance_flags { Bitfield(save_uswallow, 1); Bitfield(save_uinwater, 1); Bitfield(save_uburied, 1); + /* item types used to acomplish "special achievements"; find the target + object and you'll be flagged as having achieved something... */ + short mines_prize_type; /* luckstone */ + short soko_prize_type1; /* bag of holding or */ + short soko_prize_type2; /* amulet of reflection */ }; /* diff --git a/include/hack.h b/include/hack.h index b3a05ca67..9bc2fc403 100644 --- a/include/hack.h +++ b/include/hack.h @@ -151,6 +151,12 @@ enum game_end_types { ASCENDED }; +typedef struct strbuf { + int len; + char * str; + char buf[256]; +} strbuf_t; + #include "align.h" #include "dungeon.h" #include "monsym.h" diff --git a/include/obj.h b/include/obj.h index 75b35779d..f87caaa02 100644 --- a/include/obj.h +++ b/include/obj.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 obj.h $NHDT-Date: 1456618994 2016/02/28 00:23:14 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.53 $ */ +/* NetHack 3.6 obj.h $NHDT-Date: 1508827590 2017/10/24 06:46:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.60 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -343,13 +343,19 @@ struct obj { && !undiscovered_artifact(ART_EYES_OF_THE_OVERWORLD))) #define pair_of(o) ((o)->otyp == LENSES || is_gloves(o) || is_boots(o)) +/* 'PRIZE' values override obj->corpsenm so prizes mustn't be object types + which use that field for monster type (or other overloaded purpose) */ +#define MINES_PRIZE 1 +#define SOKO_PRIZE1 2 +#define SOKO_PRIZE2 3 #define is_mines_prize(o) \ - ((o)->otyp == LUCKSTONE && Is_mineend_level(&u.uz)) -#define is_soko_prize(o) \ - (((o)->otyp == AMULET_OF_REFLECTION \ - || (o)->otyp == BAG_OF_HOLDING) \ - && Is_sokoend_level(&u.uz)) - + ((o)->otyp == iflags.mines_prize_type \ + && (o)->record_achieve_special == MINES_PRIZE) +#define is_soko_prize(o) \ + (((o)->otyp == iflags.soko_prize_type1 \ + && (o)->record_achieve_special == SOKO_PRIZE1) \ + || ((o)->otyp == iflags.soko_prize_type2 \ + && (o)->record_achieve_special == SOKO_PRIZE2)) /* Flags for get_obj_location(). */ #define CONTAINED_TOO 0x1 diff --git a/include/prop.h b/include/prop.h index 3bbc7182f..e9f1fc0c0 100644 --- a/include/prop.h +++ b/include/prop.h @@ -11,79 +11,81 @@ * Property #0 is not used. */ /* 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 +enum prop_types { + FIRE_RES = 1, + COLD_RES, + SLEEP_RES, + DISINT_RES, + SHOCK_RES, + POISON_RES, + ACID_RES, + STONE_RES, + /* note: for the first eight properties, MR_xxx == (1 << (xxx_RES - 1)) */ + DRAIN_RES, + SICK_RES, + INVULNERABLE, + ANTIMAGIC, + /* Troubles */ + STUNNED, + CONFUSION, + BLINDED, + DEAF, + SICK, + STONED, + STRANGLED, + VOMITING, + GLIB, + SLIMED, + HALLUC, + HALLUC_RES, + FUMBLING, + WOUNDED_LEGS, + SLEEPY, + HUNGER, + /* Vision and senses */ + SEE_INVIS, + TELEPAT, + WARNING, + WARN_OF_MON, + WARN_UNDEAD, + SEARCHING, + CLAIRVOYANT, + INFRAVISION, + DETECT_MONSTERS, + /* Appearance and behavior */ + ADORNED, + INVIS, + DISPLACED, + STEALTH, + AGGRAVATE_MONSTER, + CONFLICT, + /* Transportation */ + JUMPING, + TELEPORT, + TELEPORT_CONTROL, + LEVITATION, + FLYING, + WWALKING, + SWIMMING, + MAGICAL_BREATHING, + PASSES_WALLS, + /* Physical attributes */ + SLOW_DIGESTION, + HALF_SPDAM, + HALF_PHDAM, + REGENERATION, + ENERGY_REGENERATION, + PROTECTION, + PROT_FROM_SHAPE_CHANGERS, + POLYMORPH, + POLYMORPH_CONTROL, + UNCHANGING, + FAST, + REFLECTING, + FREE_ACTION, + FIXED_ABIL, + LIFESAVED +}; #define LAST_PROP (LIFESAVED) /*** Where the properties come from ***/ diff --git a/include/rm.h b/include/rm.h index 9283ee960..b83686d8f 100644 --- a/include/rm.h +++ b/include/rm.h @@ -85,7 +85,8 @@ enum levl_typ_types { #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) \ +#define IS_DOORJOIN(typ) (IS_ROCK(typ) || (typ) == IRONBARS) +#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.. */ @@ -300,6 +301,8 @@ extern const struct symdef defsyms[MAXPCHARS]; /* defaults */ extern const struct symdef def_warnsyms[WARNCOUNT]; extern int currentgraphics; /* from drawing.c */ extern nhsym showsyms[]; +extern nhsym l_syms[]; +extern nhsym r_syms[]; extern struct symsetentry symset[NUM_GRAPHICS]; /* from drawing.c */ #define SYMHANDLING(ht) (symset[currentgraphics].handling == (ht)) diff --git a/src/bones.c b/src/bones.c index 9f5dae173..8fcb98cfc 100644 --- a/src/bones.c +++ b/src/bones.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 bones.c $NHDT-Date: 1503309019 2017/08/21 09:50:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.70 $ */ +/* NetHack 3.6 bones.c $NHDT-Date: 1508827591 2017/10/24 06:46:31 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.71 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985,1993. */ /* NetHack may be freely redistributed. See license for details. */ @@ -127,7 +127,7 @@ boolean restore; otmp->spe = 1; #endif } else if (otmp->otyp == EGG) { - otmp->spe = 0; + otmp->spe = 0; /* not "laid by you" in next game */ } else if (otmp->otyp == TIN) { /* make tins of unique monster's meat be empty */ if (otmp->corpsenm >= LOW_PM @@ -136,24 +136,30 @@ boolean restore; } 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. */ + /* 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 + /* 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 == iflags.mines_prize_type + && !Is_mineend_level(&u.uz)) + || ((otmp->otyp == iflags.soko_prize_type1 + || otmp->otyp == iflags.soko_prize_type2) + && !Is_sokoend_level(&u.uz))) { + /* "special prize" in this game becomes ordinary object + if loaded into another game */ + otmp->record_achieve_special = NON_PM; } else if (otmp->otyp == AMULET_OF_YENDOR) { /* no longer the real Amulet */ otmp->otyp = FAKE_AMULET_OF_YENDOR; @@ -186,8 +192,8 @@ sanitize_name(namebuf) char *namebuf; { int c; - boolean strip_8th_bit = - !strcmp(windowprocs.name, "tty") && !iflags.wc_eight_bit_input; + 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 diff --git a/src/botl.c b/src/botl.c index ca6c494cf..f0ee33fd0 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1794,7 +1794,7 @@ boolean from_configfile; numeric = TRUE; tmp = tmpbuf; if (strlen(tmp) > 0) { - dt = blstats[0][fld].anytype; + dt = initblstats[fld].anytype; if (percent) dt = ANY_INT; (void) s_to_anything(&hilite.value, tmp, dt); @@ -2593,7 +2593,7 @@ int fld; nopts++; } - if (fld != BL_CAP && (at == ANY_INT || at == ANY_LONG || at == ANY_UINT)) { + if (fld != BL_CAP && fld != BL_HUNGER && (at == ANY_INT || at == ANY_LONG || at == ANY_UINT)) { any = zeroany; any.a_int = onlybeh = BL_TH_VAL_ABSOLUTE; add_menu(tmpwin, NO_GLYPH, &any, 'n', 0, ATR_NONE, @@ -2609,7 +2609,7 @@ int fld; nopts++; } - if (initblstats[fld].anytype == ANY_STR || fld == BL_CAP) { + if (initblstats[fld].anytype == ANY_STR || fld == BL_CAP || fld == BL_HUNGER) { any = zeroany; any.a_int = onlybeh = BL_TH_TEXTMATCH; Sprintf(buf, "%s text match", initblstats[fld].fldname); @@ -2878,7 +2878,7 @@ choose_value: hilite.rel = TXT_VALUE; Strcpy(hilite.textmatch, aligntxt[rv]); } else if (fld == BL_HUNGER) { - const char *hutxt[] = {"Satiated", "", "Hungry", "Weak", + const char *hutxt[] = {"Satiated", (char *)0, "Hungry", "Weak", "Fainting", "Fainted", "Starved"}; int rv = query_arrayvalue(qry_buf, hutxt, @@ -3163,7 +3163,9 @@ status_hilites_viewall() datawin = create_nhwindow(NHW_TEXT); while (hlstr) { - Sprintf(buf, "OPTIONS=hilite_status: %s", hlstr->str); + Sprintf(buf, "OPTIONS=hilite_status: %.*s", + (int)(BUFSZ - sizeof "OPTIONS=hilite_status: " - 1), + hlstr->str); putstr(datawin, 0, buf); hlstr = hlstr->next; } diff --git a/src/cmd.c b/src/cmd.c index 27e05f4d8..0272ec0b9 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1494985492 2017/05/17 01:44:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.258 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1508880573 2017/10/24 21:29:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.275 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3005,7 +3005,7 @@ struct ext_func_tab extcmdlist[] = { { '\0', "terrain", "show map without obstructions", doterrain, IFBURIED | AUTOCOMPLETE }, { '\0', "therecmdmenu", - "show menu of commands you can do from here to adjacent spot", + "menu of commands you can do from here to adjacent spot", dotherecmdmenu }, { 't', "throw", "throw something", dothrow }, { '\0', "timeout", "look at timeout queue and hero's timed intrinsics", diff --git a/src/do.c b/src/do.c index d93daa6cc..58e239ca8 100644 --- a/src/do.c +++ b/src/do.c @@ -501,6 +501,12 @@ register struct obj *obj; pline_The("sink backs up, leaving %s.", doname(obj)); obj->in_use = FALSE; dropx(obj); + } else if (!rn2(5)) { + freeinv(obj); + obj->in_use = FALSE; + obj->ox = u.ux; + obj->oy = u.uy; + add_to_buried(obj); } else useup(obj); } diff --git a/src/dogmove.c b/src/dogmove.c index 5a385b6aa..200779ea3 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -1086,11 +1086,18 @@ int after; /* this is extra fast monster movement */ 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; + /* This causes unintended issues for pets trying to follow + the hero. Thus, only run it if not leashed and >5 tiles + away. */ + if (!mtmp->mleashed && + distmin(mtmp->mx, mtmp->my, u.ux, u.uy) > 5) { + 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 diff --git a/src/end.c b/src/end.c index d0fb09bc5..e1d8a6423 100644 --- a/src/end.c +++ b/src/end.c @@ -1274,8 +1274,11 @@ int how; if (have_windows) { wait_synch(); free_pickinv_cache(); /* extra persistent window if perm_invent */ - if (WIN_INVEN != WIN_ERR) + if (WIN_INVEN != WIN_ERR) { destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR; + /* precaution in case any late update_inventory() calls occur */ + flags.perm_invent = 0; + } display_nhwindow(WIN_MESSAGE, TRUE); destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR; #ifndef STATUS_HILITES @@ -1315,7 +1318,7 @@ int how; ? (const char *) ((flags.female && urole.name.f) ? urole.name.f : urole.name.m) - : (const char *) (flags.female ? "Demigoddess" : "Demigod")); + : (const char *) (flags.female ? "Demigoddess" : "Demigod")); dump_forward_putstr(endwin, 0, pbuf, done_stopprint); dump_forward_putstr(endwin, 0, "", done_stopprint); @@ -1350,6 +1353,7 @@ int how; 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); Strcat(eos(pbuf), " and Schroedinger's cat"); diff --git a/src/hacklib.c b/src/hacklib.c index 5d18fcbf7..a5d9d0c15 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -61,6 +61,11 @@ boolean friday_13th (void) int night (void) int midnight (void) + void strbuf_init (strbuf *, const char *) + void strbuf_append (strbuf *, const char *) + void strbuf_reserve (strbuf *, int) + void strbuf_empty (strbuf *) + void strbuf_nl_to_crlf (strbuf_t *) =*/ #ifdef LINT #define Static /* pacify lint */ @@ -183,7 +188,7 @@ char * strip_newline(str) char *str; { - char *p = index(str, '\n'); + char *p = rindex(str, '\n'); if (p) { if (p > str && *(p - 1) == '\r') @@ -1101,4 +1106,83 @@ midnight() return (getlt()->tm_hour == 0); } +/* strbuf_init() initializes strbuf state for use */ +void +strbuf_init(strbuf) +strbuf_t *strbuf; +{ + strbuf->str = NULL; + strbuf->len = 0; +} + +/* strbuf_append() appends given str to strbuf->str */ +void +strbuf_append(strbuf, str) +strbuf_t *strbuf; +const char *str; +{ + int len = (int) strlen(str) + 1; + + strbuf_reserve(strbuf, + len + (strbuf->str ? (int) strlen(strbuf->str) : 0)); + Strcat(strbuf->str, str); +} + +/* strbuf_reserve() ensure strbuf->str has storage for len characters */ +void +strbuf_reserve(strbuf, len) +strbuf_t *strbuf; +int len; +{ + if (strbuf->str == NULL) { + strbuf->str = strbuf->buf; + strbuf->str[0] = '\0'; + strbuf->len = (int) sizeof strbuf->buf; + } + + if (len > strbuf->len) { + char *oldbuf = strbuf->str; + + strbuf->len = len + (int) sizeof strbuf->buf; + strbuf->str = (char *) alloc(strbuf->len); + Strcpy(strbuf->str, oldbuf); + if (oldbuf != strbuf->buf) + free((genericptr_t) oldbuf); + } +} + +/* strbuf_empty() frees allocated memory and set strbuf to initial state */ +void +strbuf_empty(strbuf) +strbuf_t *strbuf; +{ + if (strbuf->str != NULL && strbuf->str != strbuf->buf) + free((genericptr_t) strbuf->str); + strbuf_init(strbuf); +} + +/* strbuf_nl_to_crlf() converts all occurences of \n to \r\n */ +void +strbuf_nl_to_crlf(strbuf) +strbuf_t *strbuf; +{ + if (strbuf->str) { + int len = (int) strlen(strbuf->str); + int count = 0; + char *cp = strbuf->str; + + while (*cp) + if (*cp++ == '\n') + count++; + if (count) { + strbuf_reserve(strbuf, len + count + 1); + for (cp = strbuf->str + len + count; count; --cp) + if ((*cp = cp[-count]) == '\n') { + *--cp = '\r'; + --count; + } + } + } +} + /*hacklib.c*/ diff --git a/src/invent.c b/src/invent.c index 0c61b3dee..edacfc547 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1498078873 2017/06/21 21:01:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.214 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1508827592 2017/10/24 06:46:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.220 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -504,12 +504,21 @@ struct obj *obj; } set_artifact_intrinsic(obj, 1, W_ART); } - if (is_mines_prize(obj) && obj->record_achieve_special) { + + /* "special achievements" aren't discoverable during play, they + end up being recorded in XLOGFILE at end of game, nowhere else; + record_achieve_special overloads corpsenm which is ordinarily + initialized to NON_PM (-1) rather than to 0; any special prize + must never be a corpse, egg, tin, figurine, or statue because + their use of obj->corpsenm for monster type would conflict, + nor be a leash (corpsenm overloaded for m_id of leashed + monster) or a novel (corpsenm overloaded for novel index) */ + if (is_mines_prize(obj)) { u.uachieve.mines_luckstone = 1; - obj->record_achieve_special = 0; - } else if (is_soko_prize(obj) && obj->record_achieve_special) { + obj->record_achieve_special = NON_PM; + } else if (is_soko_prize(obj)) { u.uachieve.finish_sokoban = 1; - obj->record_achieve_special = 0; + obj->record_achieve_special = NON_PM; } } @@ -2171,6 +2180,7 @@ const char *query; boolean want_reply; long *out_cnt; { + static const char not_carrying_anything[] = "Not carrying anything"; struct obj *otmp; char ilet, ret; char *invlet = flags.inv_order; @@ -2217,7 +2227,7 @@ long *out_cnt; ++n; if (n == 0) { - pline("Not carrying anything."); + pline("%s.", not_carrying_anything); return 0; } @@ -2305,14 +2315,24 @@ nextclass: goto nextclass; } } - if (iflags.force_invmenu && lets && want_reply) { any = zeroany; - add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Special", MENU_UNSELECTED); + add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, + "Special", MENU_UNSELECTED); any.a_char = '*'; - add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "(list everything)", MENU_UNSELECTED); + add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, + "(list everything)", MENU_UNSELECTED); + } + /* for permanent inventory where we intend to show everything but + nothing has been listed (because there isn't anyhing to list; + recognized via any.a_char still being zero; the n==0 case above + gets skipped for perm_invent), put something into the menu */ + if (flags.perm_invent && !lets && !any.a_char) { + any = zeroany; + add_menu(win, NO_GLYPH, &any, 0, 0, 0, + not_carrying_anything, MENU_UNSELECTED); + want_reply = FALSE; } - end_menu(win, query && *query ? query : (char *) 0); n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected); diff --git a/src/minion.c b/src/minion.c index d0394477b..e690d22d1 100644 --- a/src/minion.c +++ b/src/minion.c @@ -279,7 +279,8 @@ register struct monst *mtmp; if ((offer = bribe(mtmp)) >= demand) { pline("%s vanishes, laughing about cowardly mortals.", Amonnam(mtmp)); - } else if (offer > 0L && (long) rnd(40) > (demand - offer)) { + } else if (offer > 0L + && (long) rnd(5 * ACURR(A_CHA)) > (demand - offer)) { pline("%s scowls at you menacingly, then vanishes.", Amonnam(mtmp)); } else { diff --git a/src/mkobj.c b/src/mkobj.c index ab59719b7..ed59caa9a 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -223,6 +223,7 @@ boolean init, artif; return otmp; } +/* mkobj(): select a type of item from a class, use mksobj() to create it */ struct obj * mkobj(oclass, artif) char oclass; @@ -265,10 +266,10 @@ struct obj *box; n = 20; break; case CHEST: - n = 5; + n = box->olocked ? 7 : 5; break; case LARGE_BOX: - n = 3; + n = box->olocked ? 5 : 3; break; case SACK: case OILSKIN_SACK: @@ -277,7 +278,7 @@ struct obj *box; n = 0; break; } - /*else FALLTHRU*/ + /*else FALLTHRU*/ case BAG_OF_HOLDING: n = 1; break; @@ -712,6 +713,7 @@ static const char dknowns[] = { WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS, SPBOOK_CLASS, WEAPON_CLASS, TOOL_CLASS, 0 }; +/* mksobj(): create a specific type of object */ struct obj * mksobj(otyp, init, artif) int otyp; @@ -743,7 +745,7 @@ boolean artif; otmp->cknown = 0; otmp->corpsenm = NON_PM; - if (init) + if (init) { switch (let) { case WEAPON_CLASS: otmp->quan = is_multigen(otmp) ? (long) rn1(6, 6) : 1L; @@ -773,9 +775,8 @@ boolean artif; && (--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 */ + monsters on this level; create an adventurer's + corpse instead, then */ otmp->corpsenm = PM_HUMAN; } /* timer set below */ @@ -889,14 +890,13 @@ boolean artif; case BAG_OF_TRICKS: otmp->spe = rnd(20); break; - case FIGURINE: { - int tryct2 = 0; + case FIGURINE: + tryct = 0; do otmp->corpsenm = rndmonnum(); - while (is_human(&mons[otmp->corpsenm]) && tryct2++ < 30); + while (is_human(&mons[otmp->corpsenm]) && tryct++ < 30); blessorcurse(otmp, 4); break; - } case BELL_OF_OPENING: otmp->spe = 3; break; @@ -918,15 +918,12 @@ boolean artif; curse(otmp); } else blessorcurse(otmp, 10); + break; 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 POTION_CLASS: /* note: potions get some additional init below */ case SCROLL_CLASS: #ifdef MAIL if (otmp->otyp != SCR_MAIL) @@ -1012,27 +1009,36 @@ boolean artif; objects[otmp->otyp].oc_class); return (struct obj *) 0; } + } /* some things must get done (corpsenm, timers) even if init = 0 */ - switch (otmp->otyp) { + switch ((otmp->oclass == POTION_CLASS && otmp->otyp != POT_OIL) + ? POT_WATER + : 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*/ + /*FALLTHRU*/ case STATUE: case FIGURINE: if (otmp->corpsenm == NON_PM) otmp->corpsenm = rndmonnum(); - /*FALLTHRU*/ + /*FALLTHRU*/ case EGG: - /* case TIN: */ + /* case TIN: */ set_corpsenm(otmp, otmp->corpsenm); break; + case POT_OIL: + otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */ + /*FALLTHRU*/ + case POT_WATER: /* POTION_CLASS */ + otmp->fromsink = 0; /* overloads corpsenm, which was set to NON_PM */ + break; case LEASH: - otmp->leashmon = 0; + otmp->leashmon = 0; /* overloads corpsenm, which was set to NON_PM */ break; case SPE_NOVEL: otmp->novelidx = -1; /* "none of the above"; will be changed */ @@ -1412,8 +1418,10 @@ int x, y; { register struct obj *gold = g_at(x, y); - if (amount <= 0L) - amount = (long) (1 + rnd(level_difficulty() + 2) * rnd(30)); + if (amount <= 0L) { + long mul = rnd(30 / max(12-depth(&u.uz), 2)); + amount = (long) (1 + rnd(level_difficulty() + 2) * mul); + } if (gold) { gold->quan += amount; } else { diff --git a/src/mon.c b/src/mon.c index d01a79c95..a872b93a9 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2787,8 +2787,13 @@ wake_nearby() mtmp->msleeping = 0; if (!unique_corpstat(mtmp->data)) mtmp->mstrategy &= ~STRAT_WAITMASK; - if (mtmp->mtame && !mtmp->isminion) - EDOG(mtmp)->whistletime = moves; + if (mtmp->mtame) { + if (!mtmp->isminion) + EDOG(mtmp)->whistletime = moves; + /* Clear mtrack. This is to fix up a pet who is + stuck "fleeing" its master. */ + memset(mtmp->mtrack, 0, sizeof(mtmp->mtrack)); + } } } } diff --git a/src/monst.c b/src/monst.c index dd9ccfce8..fef0b8aac 100644 --- a/src/monst.c +++ b/src/monst.c @@ -1878,9 +1878,9 @@ struct permonst _mons2[] = { | M2_MALE | M2_MAGIC | M2_SHAPESHIFTER, M3_INFRAVISIBLE, HI_ZAP), #endif - MON("Vlad the Impaler", S_VAMPIRE, LVL(14, 18, -3, 80, -10), + MON("Vlad the Impaler", S_VAMPIRE, LVL(28, 26, -6, 80, -10), (G_NOGEN | G_NOCORPSE | G_UNIQ), - A(ATTK(AT_WEAP, AD_PHYS, 1, 10), ATTK(AT_BITE, AD_DRLI, 1, 10), + A(ATTK(AT_WEAP, AD_PHYS, 2, 10), ATTK(AT_BITE, AD_DRLI, 1, 12), 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, diff --git a/src/options.c b/src/options.c index b281ba695..bfd42b189 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 options.c $NHDT-Date: 1507846854 2017/10/12 22:20:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.315 $ */ +/* NetHack 3.6 options.c $NHDT-Date: 1508827592 2017/10/24 06:46:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.316 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -724,6 +724,12 @@ initoptions_init() iflags.travelcc.x = iflags.travelcc.y = -1; + /* for "special achievement" tracking (see obj.h, + create_object(sp_lev.c), addinv_core1(invent.c) */ + iflags.mines_prize_type = LUCKSTONE; + iflags.soko_prize_type1 = BAG_OF_HOLDING; + iflags.soko_prize_type2 = AMULET_OF_REFLECTION; + /* 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); @@ -5108,6 +5114,7 @@ boolean setinitial, setfromfile; assign_graphics(ROGUESET); } else if (!rogueflag) assign_graphics(PRIMARY); + preference_update("symset"); need_redraw = TRUE; return TRUE; diff --git a/src/pager.c b/src/pager.c index d7fc456b8..5d9f4ddc1 100644 --- a/src/pager.c +++ b/src/pager.c @@ -195,7 +195,7 @@ struct obj **obj_p; glyph among floor and buried objects; when !Blind, any buried object's glyph will have been replaced by whatever is present on the surface as soon as we moved next to its spot */ - && otmp->where == OBJ_FLOOR /* not buried */ + && (fakeobj || otmp->where == OBJ_FLOOR) /* not buried */ /* terrain mode views what's already known, doesn't learn new stuff */ && !iflags.terrainmode) /* so don't set dknown when in terrain mode */ otmp->dknown = 1; /* if a pile, clearly see the top item only */ diff --git a/src/role.c b/src/role.c index 5a1a4ab56..fd23f3adb 100644 --- a/src/role.c +++ b/src/role.c @@ -1714,7 +1714,7 @@ plnamesuffix() do { if (!*plname) - askname(); /* fill plname[] if necessary */ + askname(); /* fill plname[] if necessary, or set defer_plname */ /* Look for tokens delimited by '-' */ if ((eptr = index(plname, '-')) != (char *) 0) @@ -1735,7 +1735,7 @@ plnamesuffix() else if ((i = str2align(sptr)) != ROLE_NONE) flags.initalign = i; } - } while (!*plname); + } while (!*plname && !iflags.defer_plname); /* commas in the plname confuse the record file, convert to spaces */ for (sptr = plname; *sptr; sptr++) { diff --git a/src/sp_lev.c b/src/sp_lev.c index 5323d4665..5d3d69778 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -1,4 +1,4 @@ -/* 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 $ */ +/* NetHack 3.6 sp_lev.c $NHDT-Date: 1508879840 2017/10/24 21:17:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.90 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -198,13 +198,14 @@ 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; +static boolean splev_init_present = FALSE; +static boolean icedpools = FALSE; +static int mines_prize_count = 0, soko_prize_count = 0; /* achievements */ -struct monst *invent_carrying_monster = NULL; +static struct obj *container_obj[MAX_CONTAINMENT]; +static int container_idx = 0; +static struct monst *invent_carrying_monster = NULL; #define SPLEV_STACK_RESERVE 128 @@ -1881,6 +1882,7 @@ struct mkroom *croom; } } else { struct obj *cobj = container_obj[container_idx - 1]; + remove_object(otmp); if (cobj) { (void) add_to_container(cobj, otmp); @@ -1941,12 +1943,31 @@ struct mkroom *croom; } } - /* 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 (is_mines_prize(otmp) || is_soko_prize(otmp)) { - otmp->record_achieve_special = 1; + if (o->id != -1) { + static const char prize_warning[] = "multiple prizes on %s level"; + + /* if this is a specific item of the right type and it is being + created on the right level, flag it as the designated item + used to detect a special achievement (to whit, reaching and + exploring the target level, although the exploration part + might be short-circuited if a monster brings object to hero) */ + if (Is_mineend_level(&u.uz)) { + if (otmp->otyp == iflags.mines_prize_type) { + otmp->record_achieve_special = MINES_PRIZE; + if (++mines_prize_count > 1) + impossible(prize_warning, "mines end"); + } + } else if (Is_sokoend_level(&u.uz)) { + if (otmp->otyp == iflags.soko_prize_type1) { + otmp->record_achieve_special = SOKO_PRIZE1; + if (++soko_prize_count > 1) + impossible(prize_warning, "sokoban end"); + } else if (otmp->otyp == iflags.soko_prize_type2) { + otmp->record_achieve_special = SOKO_PRIZE2; + if (++soko_prize_count > 1) + impossible(prize_warning, "sokoban end"); + } + } } stackobj(otmp); @@ -4176,6 +4197,13 @@ genericptr_t arg; if (typ < D_CLOSED) typ = D_CLOSED; } + + if (((isok(x-1,y) && IS_DOORJOIN(levl[x-1][y].typ)) || !isok(x-1,y)) + || (isok(x+1,y) && IS_DOORJOIN(levl[x+1][y].typ)) || !isok(x+1,y)) + levl[x][y].horizontal = 1; + else + levl[x][y].horizontal = 0; + levl[x][y].doormask = typ; SpLev_Map[x][y] = 1; } @@ -5186,7 +5214,7 @@ sp_lev *lvl; long room_stack = 0; unsigned long max_execution = SPCODER_MAX_RUNTIME; struct sp_coder *coder = - (struct sp_coder *) alloc(sizeof(struct sp_coder)); + (struct sp_coder *) alloc(sizeof (struct sp_coder)); coder->frame = frame_new(0); coder->stack = NULL; @@ -5200,9 +5228,14 @@ sp_lev *lvl; splev_init_present = FALSE; icedpools = FALSE; + /* achievement tracking; static init would suffice except we need to + reset if #wizmakemap is used to recreate mines' end or sokoban end; + once either level is created, these values can be forgotten */ + mines_prize_count = soko_prize_count = 0; if (wizard) { char *met = nh_getenv("SPCODER_MAX_RUNTIME"); + if (met && met[0] == '1') max_execution = (1 << 30) - 1; } diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index d62d234cc..a18157639 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -139,6 +139,15 @@ char *argv[]; /* use STDERR by default _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ +/* Heap Debugging + _CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) + | _CRTDBG_ALLOC_MEM_DF + | _CRTDBG_CHECK_ALWAYS_DF + | _CRTDBG_CHECK_CRT_DF + | _CRTDBG_DELAY_FREE_MEM_DF + | _CRTDBG_LEAK_CHECK_DF); + _CrtSetBreakAlloc(1423); +*/ # endif #endif diff --git a/sys/share/pcsys.c b/sys/share/pcsys.c index 085956c76..5746b778c 100644 --- a/sys/share/pcsys.c +++ b/sys/share/pcsys.c @@ -546,6 +546,8 @@ msexit() getreturn("to end"); synch_cursor(); #endif + getreturn_enabled = TRUE; + wait_synch(); return; } #endif /* MICRO || WIN32 || OS2 */ diff --git a/sys/unix/hints/linux-x11 b/sys/unix/hints/linux-x11 index a0d5552e2..05d7e7304 100644 --- a/sys/unix/hints/linux-x11 +++ b/sys/unix/hints/linux-x11 @@ -20,7 +20,7 @@ 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 +CFLAGS=-g -O -I../include -DNOTPARMDECL CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" CFLAGS+=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" CFLAGS+=-DX11_GRAPHICS -DDEFAULT_WINDOW_SYS=\"X11\" -DNOTTYGRAPHICS diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 2e8f41330..b9ab44526 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -55,6 +55,7 @@ char *argv[]; #endif boolean exact_username; boolean resuming = FALSE; /* assume new game */ + boolean plsel_once = FALSE; sys_early_init(); @@ -237,19 +238,6 @@ char *argv[]; (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() */ @@ -266,7 +254,24 @@ char *argv[]; * We'll return here if new game player_selection() renames the hero. */ attempt_restore: - if ((fd = restore_saved_game()) >= 0) { + + /* + * 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). + */ + if (*plname) { + getlock(); + program_state.preserve_locks = 0; /* after getlock() */ + } + + if (*plname && (fd = restore_saved_game()) >= 0) { const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1); (void) chmod(fq_save, 0); /* disallow parallel restores */ @@ -297,12 +302,17 @@ attempt_restore: } if (!resuming) { + boolean neednewlock = (!*plname); /* 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 || iflags.defer_plname || neednewlock) { + if (!plsel_once) + player_selection(); + plsel_once = TRUE; + if (neednewlock && *plname) + goto attempt_restore; if (iflags.renameinprogress) { /* player has renamed the hero while selecting role; if locking alphabetically, the existing lock file diff --git a/sys/winnt/Makefile.msc b/sys/winnt/Makefile.msc index 380019228..93324245e 100644 --- a/sys/winnt/Makefile.msc +++ b/sys/winnt/Makefile.msc @@ -247,8 +247,8 @@ 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 +baselibs = kernel32.lib $(optlibs) $(winsocklibs) advapi32.lib gdi32.lib +winlibs = $(baselibs) user32.lib comdlg32.lib winspool.lib # for Windows applications that use the C Run-Time libraries conlibs = $(baselibs) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 64bea743c..3ac469ea8 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -44,6 +44,10 @@ int FDECL(process_keystroke, (INPUT_RECORD *, boolean *, BOOLEAN_P numberpad, int portdebug)); static void NDECL(init_ttycolor); static void NDECL(really_move_cursor); +static void NDECL(check_and_set_font); +static boolean NDECL(check_font_widths); +static void NDECL(set_known_good_console_font); +static void NDECL(restore_original_console_font); /* Win32 Console handles for input and output */ HANDLE hConIn; @@ -54,6 +58,11 @@ CONSOLE_SCREEN_BUFFER_INFO csbi, origcsbi; COORD ntcoord; INPUT_RECORD ir; +/* Support for changing console font if existing glyph widths are too wide */ +boolean console_font_changed; +CONSOLE_FONT_INFOEX original_console_font_info; +UINT original_console_code_page; + extern boolean getreturn_enabled; /* from sys/share/pcsys.c */ extern int redirect_stdout; @@ -148,6 +157,10 @@ KEYHANDLERNAME pKeyHandlerName; void gettty() { + console_font_changed = FALSE; + + check_and_set_font(); + #ifndef TEXTCOLOR int k; #endif @@ -171,6 +184,8 @@ const char *s; end_screen(); if (s) raw_print(s); + + restore_original_console_font(); } /* called by init_nhwindows() and resume_nhwindows() */ @@ -514,45 +529,47 @@ char ch; * Overrides wintty.c function of the same name * for win32. It is used for glyphs only, not text. */ + +/* 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 +}; + 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 - }; boolean inverse = FALSE; unsigned char ch = (unsigned char) in_ch; @@ -853,6 +870,8 @@ const char *pref; toggle_mouse_support(); #endif } + if (stricmp(pref, "symset") == 0) + check_and_set_font(); return; } @@ -1466,4 +1485,179 @@ GetConsoleHwnd(void) return hwndFound; } #endif /*CHANGE_COLOR*/ + +static int CALLBACK EnumFontCallback( + const LOGFONTW * lf, const TEXTMETRICW * tm, DWORD fontType, LPARAM lParam) +{ + LOGFONTW * lf_ptr = (LOGFONTW *) lParam; + *lf_ptr = *lf; + return 0; +} + +/* check_and_set_font ensures that the current font will render the symbols + * that are currently being used correctly. If they will not be rendered + * correctly, then it will change the font to a known good font. + */ +void +check_and_set_font() +{ + if (!check_font_widths()) { + raw_print("WARNING: glyphs too wide in console font." + " Changing code page to 437 and font to Consolas\n"); + set_known_good_console_font(); + } +} + +/* check_font_widths returns TRUE if all glyphs in current console font + * fit within the width of a single console cell. + */ +boolean +check_font_widths() +{ + CONSOLE_FONT_INFOEX console_font_info; + console_font_info.cbSize = sizeof(console_font_info); + BOOL success = GetCurrentConsoleFontEx(hConOut, FALSE, + &console_font_info); + + /* get console window and DC + * NOTE: the DC from the console window does not have the correct + * font selected at this point. + */ + HWND hWnd = GetConsoleWindow(); + HDC hDC = GetDC(hWnd); + + LOGFONTW logical_font; + logical_font.lfCharSet = DEFAULT_CHARSET; + wcscpy(logical_font.lfFaceName, console_font_info.FaceName); + logical_font.lfPitchAndFamily = 0; + + /* getting matching console font */ + LOGFONTW matching_log_font = { 0 }; + EnumFontFamiliesExW(hDC, &logical_font, EnumFontCallback, + (LPARAM) &matching_log_font, 0); + + if (matching_log_font.lfHeight == 0) { + raw_print("Unable to enumerate system fonts\n"); + return FALSE; + } + + /* create font matching console font */ + LOGFONTW console_font_log_font = matching_log_font; + console_font_log_font.lfWeight = console_font_info.FontWeight; + console_font_log_font.lfHeight = console_font_info.dwFontSize.Y; + console_font_log_font.lfWidth = 0; + HFONT console_font = CreateFontIndirectW(&console_font_log_font); + + if (console_font == NULL) { + raw_print("Unable to create console font\n"); + return FALSE; + } + + /* select font */ + HGDIOBJ saved_font = SelectObject(hDC, console_font); + + /* determine whether it is a true type font */ + TEXTMETRICA tm; + success = GetTextMetricsA(hDC, &tm); + + if (!success) { + raw_print("Unable to get console font text metrics\n"); + goto clean_up; + } + + boolean isTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) != 0; + + /* determine which glyphs are used */ + boolean used[256]; + memset(used, 0, sizeof(used)); + for (int i = 0; i < SYM_MAX; i++) { + used[l_syms[i]] = TRUE; + used[r_syms[i]] = TRUE; + } + + int wcUsedCount = 0; + wchar_t wcUsed[256]; + for (int i = 0; i < sizeof(used); i++) + if (used[i]) + wcUsed[wcUsedCount++] = cp437[i]; + + /* measure the set of used glyphs to ensure they fit */ + boolean all_glyphs_fit = TRUE; + + for (int i = 0; i < wcUsedCount; i++) { + int width; + if (isTrueType) { + ABC abc; + success = GetCharABCWidthsW(hDC, wcUsed[i], wcUsed[i], &abc); + width = abc.abcA + abc.abcB + abc.abcC; + } else { + success = GetCharWidthW(hDC, wcUsed[i], wcUsed[i], &width); + } + + if (success && width > console_font_info.dwFontSize.X) { + all_glyphs_fit = FALSE; + break; + } + } + +clean_up: + + SelectObject(hDC, saved_font); + DeleteObject(console_font); + + return all_glyphs_fit; +} + +/* set_known_good_console_font sets the code page and font used by the console + * to settings know to work well with NetHack. It also saves the original + * settings so that they can be restored prior to NetHack exit. + */ +void +set_known_good_console_font() +{ + CONSOLE_FONT_INFOEX console_font_info; + console_font_info.cbSize = sizeof(console_font_info); + BOOL success = GetCurrentConsoleFontEx(hConOut, FALSE, + &console_font_info); + + console_font_changed = TRUE; + original_console_font_info = console_font_info; + original_console_code_page = GetConsoleOutputCP(); + + wcscpy_s(console_font_info.FaceName, + sizeof(console_font_info.FaceName) + / sizeof(console_font_info.FaceName[0]), + L"Consolas"); + + success = SetConsoleOutputCP(437); + if (!success) + raw_print("Unable to set console code page to 437\n"); + + success = SetCurrentConsoleFontEx(hConOut, FALSE, &console_font_info); + if (!success) + raw_print("Unable to set console font to Consolas\n"); +} + +/* restore_original_console_font will restore the console font and code page + * settings to what they were when NetHack was launched. + */ +void +restore_original_console_font() +{ + if (console_font_changed) { + BOOL success; + raw_print("Restoring original font and code page\n"); + success = SetConsoleOutputCP(original_console_code_page); + if (!success) + raw_print("Unable to restore original code page\n"); + + success = SetCurrentConsoleFontEx(hConOut, FALSE, + &original_console_font_info); + if (!success) + raw_print("Unable to restore original font\n"); + + console_font_changed = FALSE; + } +} + #endif /* WIN32 */ diff --git a/win/X11/tile2x11.c b/win/X11/tile2x11.c index a51cb75cd..cf2d1ffe3 100644 --- a/win/X11/tile2x11.c +++ b/win/X11/tile2x11.c @@ -157,7 +157,7 @@ FILE *fp; Fprintf(fp, "\",\n"); } - return Fprintf(fp, "};\n") >= 0; + return fprintf(fp, "};\n") >= 0; } #endif /* USE_XPM */ diff --git a/win/X11/winX.c b/win/X11/winX.c index ff9b0ff51..6b285a2e5 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -1474,18 +1474,11 @@ X11_askname() { Widget popup, dialog; Arg args[1]; - char *defplname = (char *)0; - -#ifdef UNIX - defplname = get_login_name(); -#endif - (void) strncpy(plname, defplname ? defplname : "Mumbles", - sizeof plname - 1); - plname[sizeof plname - 1] = '\0'; if (iflags.wc_player_selection == VIA_DIALOG) { /* X11_player_selection_dialog() handles name query */ plsel_ask_name = TRUE; + iflags.defer_plname = TRUE; return; } /* else iflags.wc_player_selection == VIA_PROMPTS */ diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 8ddb62a79..945e35fc4 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -352,8 +352,13 @@ plsel_dialog_acceptvalues() XtSetArg(args[0], nhStr(XtNstring), &s); XtGetValues(plsel_name_input, args, ONE); + (void) strncpy(plname, (char *) s, sizeof plname - 1); plname[sizeof plname - 1] = '\0'; + (void) mungspaces(plname); + if (strlen(plname) < 1) + (void) strcpy(plname, "Mumbles"); + iflags.renameinprogress = FALSE; } /* ARGSUSED */ @@ -1553,6 +1558,17 @@ void X11_player_selection() { if (iflags.wc_player_selection == VIA_DIALOG) { + if (!*plname) { +#ifdef UNIX + char *defplname = get_login_name(); +#else + char *defplname = (char *)0; +#endif + (void) strncpy(plname, defplname ? defplname : "Mumbles", + sizeof plname - 1); + plname[sizeof plname - 1] = '\0'; + iflags.renameinprogress = TRUE; + } X11_player_selection_dialog(); } else { /* iflags.wc_player_selection == VIA_PROMPTS */ X11_player_selection_prompts(); diff --git a/win/win32/mhdlg.c b/win/win32/mhdlg.c index efd35dff8..a91eecf20 100644 --- a/win/win32/mhdlg.c +++ b/win/win32/mhdlg.c @@ -10,6 +10,8 @@ #include "resource.h" #include "mhdlg.h" +#include + /*---------------------------------------------------------------*/ /* data for getlin dialog */ struct getlin_data { @@ -256,34 +258,51 @@ ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } /*---------------------------------------------------------------*/ -/* player selector dialog data */ -struct plsel_data { - int *selection; -}; +/* player selector dialog */ +typedef struct plsel_data { + int config_race; + int config_role; + int config_gender; + int config_alignment; + HWND control_role; + HWND control_race; + HWND control_genders[ROLE_GENDERS]; + HWND control_aligns[ROLE_ALIGNS]; + int role_count; + int race_count; + HWND focus; +} plsel_data_t; 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); +static void plselAdjustSelections(HWND hWnd); +static boolean plselRandomize(plsel_data_t * data); +static BOOL plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam); -int -mswin_player_selection_window(int *selection) +boolean +mswin_player_selection_window() { INT_PTR ret; - struct plsel_data data; + plsel_data_t data; + boolean ok = TRUE; - /* init dialog data */ - ZeroMemory(&data, sizeof(data)); - data.selection = selection; + /* save away configuration settings */ + data.config_role = flags.initrole; + data.config_race = flags.initrace; + data.config_gender = flags.initgend; + data.config_alignment = flags.initalign; - /* create modal dialog */ - ret = DialogBoxParam( - GetNHApp()->hApp, MAKEINTRESOURCE(IDD_PLAYER_SELECTOR), - GetNHApp()->hMainWnd, PlayerSelectorDlgProc, (LPARAM) &data); - if (ret == -1) - panic("Cannot create getlin window"); + if (!plselRandomize(&data)) { + /* create modal dialog */ + ret = DialogBoxParam( + GetNHApp()->hApp, MAKEINTRESOURCE(IDD_PLAYER_SELECTOR), + GetNHApp()->hMainWnd, PlayerSelectorDlgProc, (LPARAM) &data); + if (ret == -1) + panic("Cannot create getlin window"); + ok = (ret == IDOK); + } - return (int) ret; + return ok; } INT_PTR CALLBACK @@ -315,11 +334,94 @@ PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /* init dialog */ plselInitDialog(hWnd); - /* set focus on the role checkbox (random) field */ - SetFocus(GetDlgItem(hWnd, IDC_PLSEL_ROLE_RANDOM)); + /* tell windows to set the focus */ + return TRUE; + break; - /* tell windows we set the focus */ - return FALSE; + case WM_DRAWITEM: + if (wParam == IDC_PLSEL_ROLE_LIST || wParam == IDC_PLSEL_RACE_LIST) + return plselDrawItem(hWnd, wParam, lParam); + break; + + case WM_NOTIFY: + { + LPNMHDR nmhdr = (LPNMHDR)lParam; + HWND control = nmhdr->hwndFrom; + + data = (struct plsel_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA); + + switch (nmhdr->code) { + case LVN_KEYDOWN: + { + LPNMLVKEYDOWN lpnmkeydown = (LPNMLVKEYDOWN) lParam; + + if (lpnmkeydown->wVKey == ' ') { + if (control == data->control_role) { + int i = ListView_GetNextItem(data->control_role, -1, LVNI_FOCUSED); + assert(i == -1 || ListView_GetNextItem(data->control_role, i, LVNI_FOCUSED) == -1); + flags.initrole = i; + plselAdjustSelections(hWnd); + } else if (control == data->control_race) { + int i = ListView_GetNextItem(data->control_race, -1, LVNI_FOCUSED); + assert(i == -1 || ListView_GetNextItem(data->control_race, i, LVNI_FOCUSED) == -1); + if (ok_race(flags.initrole, i, ROLE_RANDOM, ROLE_RANDOM)) { + flags.initrace = i; + plselAdjustSelections(hWnd); + } + } + } + } + break; + case NM_CLICK: + { + LPNMLISTVIEW lpnmitem = (LPNMLISTVIEW)lParam; + int i = lpnmitem->iItem; + if (i == -1) + return FALSE; + if (control == data->control_role) { + flags.initrole = i; + plselAdjustSelections(hWnd); + } else if(control == data->control_race) { + if (ok_race(flags.initrole, i, ROLE_RANDOM, ROLE_RANDOM)) { + flags.initrace = i; + plselAdjustSelections(hWnd); + } + } + } + break; + case NM_KILLFOCUS: + { + char buf[64]; + sprintf(buf, "KILLFOCUS %lx\n", (unsigned long) control); + OutputDebugStringA(buf); + + if (data->focus == data->control_race) { + data->focus = NULL; + ListView_RedrawItems(data->control_race, 0, data->race_count - 1); + } else if (data->focus == data->control_role) { + data->focus = NULL; + ListView_RedrawItems(data->control_role, 0, data->role_count - 1); + } + } + break; + case NM_SETFOCUS: + { + char buf[64]; + sprintf(buf, "SETFOCUS %lx\n", (unsigned long) control); + OutputDebugStringA(buf); + data->focus = control; + + if (control == data->control_race) { + data->focus = data->control_race; + plselAdjustSelections(hWnd); + } else if (control == data->control_role) { + data->focus = data->control_role; + plselAdjustSelections(hWnd); + } + } + break; + } + } break; case WM_COMMAND: @@ -327,483 +429,361 @@ PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 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); - } + EndDialog(hWnd, wParam); 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: + case IDC_PLSEL_RANDOM: + plselRandomize(data); + plselAdjustSelections(hWnd); + return TRUE; + + case IDC_PLSEL_GENDER_MALE: + case IDC_PLSEL_GENDER_FEMALE: 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); + int i = LOWORD(wParam) - IDC_PLSEL_GENDER_MALE; + if (ok_gend(flags.initrole, flags.initrace, i, ROLE_RANDOM)) { + flags.initgend = i; + plselAdjustSelections(hWnd); + } } break; - case IDC_PLSEL_RACE_RANDOM: + + case IDC_PLSEL_ALIGN_LAWFUL: + case IDC_PLSEL_ALIGN_NEUTRAL: + case IDC_PLSEL_ALIGN_CHAOTIC: if (HIWORD(wParam) == BN_CLICKED) { - EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), - SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) - == BST_UNCHECKED); + int i = LOWORD(wParam) - IDC_PLSEL_ALIGN_LAWFUL; + if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { + flags.initalign = i; + plselAdjustSelections(hWnd); + } } 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) { + struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA); TCHAR wbuf[BUFSZ]; + LVCOLUMN lvcol; + data->control_role = GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST); + data->control_race = GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST); + + ZeroMemory(&lvcol, sizeof(lvcol)); + lvcol.mask = LVCF_WIDTH; + lvcol.cx = GetSystemMetrics(SM_CXFULLSCREEN); + + /* build role list */ + ListView_InsertColumn(data->control_role, 0, &lvcol); + data->role_count = 0; + for (int i = 0; roles[i].name.m; i++) { + LVITEM lvitem; + ZeroMemory(&lvitem, sizeof(lvitem)); + + lvitem.mask = LVIF_STATE | LVIF_TEXT; + lvitem.iItem = i; + lvitem.iSubItem = 0; + lvitem.state = 0; + lvitem.stateMask = LVIS_FOCUSED; + if (flags.female && roles[i].name.f) + lvitem.pszText = NH_A2W(roles[i].name.f, wbuf, BUFSZ); + else + lvitem.pszText = NH_A2W(roles[i].name.m, wbuf, BUFSZ); + if (ListView_InsertItem(data->control_role, &lvitem) == -1) { + panic("cannot insert menu item"); + } + data->role_count++; + } + + /* build race list */ + ListView_InsertColumn(data->control_race, 0, &lvcol); + data->race_count = 0; + for (int i = 0; races[i].noun; i++) { + LVITEM lvitem; + ZeroMemory(&lvitem, sizeof(lvitem)); + + lvitem.mask = LVIF_STATE | LVIF_TEXT; + lvitem.iItem = i; + lvitem.iSubItem = 0; + lvitem.state = 0; + lvitem.stateMask = LVIS_FOCUSED; + lvitem.pszText = NH_A2W(races[i].noun, wbuf, BUFSZ); + if (ListView_InsertItem(data->control_race, &lvitem) == -1) { + panic("cannot insert menu item"); + } + data->race_count++; + } + + for(int i = 0; i < ROLE_GENDERS; i++) + data->control_genders[i] = GetDlgItem(hWnd, IDC_PLSEL_GENDER_MALE + i); + + for(int i = 0; i < ROLE_ALIGNS; i++) + data->control_aligns[i] = GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LAWFUL + i); + + /* set gender radio button state */ + for (int i = 0; i < ROLE_GENDERS; i++) + Button_Enable(data->control_genders[i], TRUE); + + Button_SetCheck(data->control_genders[0], BST_CHECKED); + + /* set alignment radio button state */ + for (int i = 0; i < ROLE_ALIGNS; i++) + Button_Enable(data->control_aligns[i], TRUE); + + Button_SetCheck(data->control_aligns[0], BST_CHECKED); /* 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; - } - } + plselRandomize(data); /* populate select boxes */ - plselAdjustLists(hWnd, -1); + plselAdjustSelections(hWnd); - /* 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); - } + /* set tab order */ + SetWindowPos(GetDlgItem(hWnd, IDCANCEL), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + SetWindowPos(GetDlgItem(hWnd, IDC_PLSEL_RANDOM), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + SetWindowPos(GetDlgItem(hWnd, IDOK), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + for(int i = ROLE_GENDERS - 1; i >= 0; i--) + SetWindowPos(data->control_genders[i], NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + for(int i = ROLE_ALIGNS - 1; i >= 0; i--) + SetWindowPos(data->control_aligns[i], NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + SetWindowPos(data->control_race, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + SetWindowPos(data->control_role, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - /* 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) +plselAdjustSelections(HWND hWnd) { - HWND control_role, control_race, control_gender, control_align; - int initrole, initrace, initgend, initalign; - int i; - LRESULT ind; - int valid_opt; - TCHAR wbuf[255]; + struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA); - /* 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); + if (!ok_race(flags.initrole, flags.initrace, ROLE_RANDOM, ROLE_RANDOM)) + flags.initrace = pick_race(flags.initrole, ROLE_RANDOM, ROLE_RANDOM, ROLE_RANDOM); - /* 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); + if (!ok_gend(flags.initrole, flags.initrace, flags.initgend, ROLE_RANDOM)) + flags.initgend = pick_gend(flags.initrole, flags.initrace, ROLE_RANDOM , ROLE_RANDOM); - ind = SendMessage(control_race, CB_GETCURSEL, 0, 0); - initrace = (ind == LB_ERR) - ? flags.initrace - : (int) SendMessage(control_race, CB_GETITEMDATA, ind, 0); + if (!ok_align(flags.initrole, flags.initrace, flags.initgend, flags.initalign)) + flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend , ROLE_RANDOM); - ind = SendMessage(control_gender, CB_GETCURSEL, 0, 0); - initgend = (ind == LB_ERR) ? flags.initgend - : (int) SendMessage(control_gender, - CB_GETITEMDATA, ind, 0); + ListView_RedrawItems(data->control_role, 0, data->role_count - 1); + ListView_RedrawItems(data->control_race, 0, data->race_count - 1); - 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; + /* set gender radio button state */ + for (int i = 0; i < ROLE_GENDERS; i++) { + BOOL enable = ok_gend(flags.initrole, flags.initrace, i, flags.initalign); + Button_Enable(data->control_genders[i], enable); + LRESULT state = Button_GetCheck(data->control_genders[i]); + if (state == BST_CHECKED && flags.initgend != i) + Button_SetCheck(data->control_genders[i], BST_UNCHECKED); + if (state == BST_UNCHECKED && flags.initgend == i) + Button_SetCheck(data->control_genders[i], BST_CHECKED); } - /* 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; + /* set alignment radio button state */ + for (int i = 0; i < ROLE_ALIGNS; i++) { + BOOL enable = ok_align(flags.initrole, flags.initrace, flags.initgend, i); + Button_Enable(data->control_aligns[i], enable); + LRESULT state = Button_GetCheck(data->control_aligns[i]); + if (state == BST_CHECKED && flags.initalign != i) + Button_SetCheck(data->control_aligns[i], BST_UNCHECKED); + if (state == BST_UNCHECKED && flags.initalign == i) + Button_SetCheck(data->control_aligns[i], BST_CHECKED); } - /* 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) +plselFinalSelection(HWND hWnd) { - LRESULT ind; + int role = flags.initrole; + int race = flags.initrace; + int gender = flags.initgend; + int alignment = flags.initalign; - 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; - } - } + assert(role != ROLE_RANDOM && role != ROLE_NONE); + assert(race != ROLE_RANDOM && race != ROLE_NONE); + assert(gender != ROLE_RANDOM && gender != ROLE_NONE); + assert(alignment != ROLE_RANDOM && alignment != ROLE_NONE); + assert(ok_role(role, race, gender, alignment)); + assert(ok_race(role, race, gender, alignment)); + assert(ok_gend(role, race, gender, alignment)); + assert(ok_align(role, race, gender, alignment)); + + return TRUE; +} + +static boolean plselRandomize(plsel_data_t * data) +{ + boolean fully_specified = TRUE; + + // restore back to configuration settings + flags.initrole = data->config_role; + flags.initrace = data->config_race; + flags.initgend = data->config_gender; + flags.initalign = data->config_alignment; + + if (!flags.randomall) { + if(flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE + || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE) + fully_specified = FALSE; + } + + if (flags.initrole == ROLE_NONE) + flags.initrole = ROLE_RANDOM; + if (flags.initrace == ROLE_NONE) + flags.initrace = ROLE_RANDOM; + if (flags.initgend == ROLE_NONE) + flags.initgend = ROLE_RANDOM; + if (flags.initalign == ROLE_NONE) + flags.initalign = ROLE_RANDOM; + + rigid_role_checks(); + + int role = flags.initrole; + int race = flags.initrace; + int gender = flags.initgend; + int alignment = flags.initalign; + + assert(role != ROLE_RANDOM && role != ROLE_NONE); + assert(race != ROLE_RANDOM && race != ROLE_NONE); + assert(gender != ROLE_RANDOM && gender != ROLE_NONE); + assert(alignment != ROLE_RANDOM && alignment != ROLE_NONE); + + if (!ok_role(role, race, gender, alignment)) { + fully_specified = FALSE; + flags.initrole = ROLE_RANDOM; + } + + if (!ok_race(role, race, gender, alignment)) { + fully_specified = FALSE; + flags.initrace = ROLE_RANDOM; + } + + if (!ok_gend(role, race, gender, alignment)) { + fully_specified = FALSE; + flags.initgend = ROLE_RANDOM; + } + + if(!ok_align(role, race, gender, alignment)) + { + fully_specified = FALSE; + flags.initalign = ROLE_RANDOM; + } + + rigid_role_checks(); + + role = flags.initrole; + race = flags.initrace; + gender = flags.initgend; + alignment = flags.initalign; + + assert(role != ROLE_RANDOM && role != ROLE_NONE); + assert(race != ROLE_RANDOM && race != ROLE_NONE); + assert(gender != ROLE_RANDOM && gender != ROLE_NONE); + assert(alignment != ROLE_RANDOM && alignment != ROLE_NONE); + assert(ok_role(role, race, gender, alignment)); + assert(ok_race(role, race, gender, alignment)); + assert(ok_gend(role, race, gender, alignment)); + assert(ok_align(role, race, gender, alignment)); + + return fully_specified; +} + +/*-----------------------------------------------------------------------------*/ +BOOL +plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) +{ + LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) lParam; + struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA); + + /* If there are no list box items, skip this message. */ + if (lpdis->itemID < 0) + return FALSE; + + HWND control = GetDlgItem(hWnd, wParam); + int i = lpdis->itemID; + + { + char buf[64]; + sprintf(buf, "DRAW %lx %d\n", (unsigned long)control, i); + OutputDebugStringA(buf); + } + + const char * string; + + boolean ok = TRUE; + boolean selected; + + if (wParam == IDC_PLSEL_ROLE_LIST) { + if (flags.female && roles[i].name.f) + string = roles[i].name.f; + else + string = roles[i].name.m; + selected = (flags.initrole == i); + } else { + assert(wParam == IDC_PLSEL_RACE_LIST); + ok = ok_race(flags.initrole, i, ROLE_RANDOM, ROLE_RANDOM); + string = races[i].noun; + selected = (flags.initrace == i); + } + + SetBkMode(lpdis->hDC, OPAQUE); + HBRUSH brush; + if (selected) { + brush = CreateSolidBrush(RGB(0, 0, 0)); + SetTextColor(lpdis->hDC, RGB(255, 255, 255)); + SetBkColor(lpdis->hDC, RGB(0, 0, 0)); + } else { + brush = CreateSolidBrush(RGB(255, 255, 255)); + if (!ok) + SetTextColor(lpdis->hDC, RGB(220, 0, 0)); + else + SetTextColor(lpdis->hDC, RGB(0, 0, 0)); + SetBkColor(lpdis->hDC, RGB(255, 255, 255)); + } + + FillRect(lpdis->hDC, &lpdis->rcItem, brush); + RECT rect = lpdis->rcItem; + rect.left += 5; + DrawTextA(lpdis->hDC, string, strlen(string), &rect, + DT_LEFT | DT_SINGLELINE | DT_VCENTER); + + if (data->focus == control) { + if (lpdis->itemState & LVIS_FOCUSED) { + /* draw focus rect */ + RECT client_rt; + + GetClientRect(lpdis->hwndItem, &client_rt); + SetRect(&rect, client_rt.left, lpdis->rcItem.top, + client_rt.left + ListView_GetColumnWidth(lpdis->hwndItem, 0), + lpdis->rcItem.bottom); + DrawFocusRect(lpdis->hDC, &rect); + + { + char buf[64]; + sprintf(buf, "FOCUS %lx %d\n", (unsigned long)control, i); + OutputDebugStringA(buf); + } + } + } + + DeleteObject(brush); return TRUE; } diff --git a/win/win32/mhdlg.h b/win/win32/mhdlg.h index 60f392901..c028fc82b 100644 --- a/win/win32/mhdlg.h +++ b/win/win32/mhdlg.h @@ -12,6 +12,6 @@ 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); +boolean mswin_player_selection_window(); #endif /* MSWINDlgWindow_h */ diff --git a/win/win32/mhmsgwnd.c b/win/win32/mhmsgwnd.c index 40b4791ef..22b0fdd9f 100644 --- a/win/win32/mhmsgwnd.c +++ b/win/win32/mhmsgwnd.c @@ -245,6 +245,25 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (wParam) { case MSNH_MSG_PUTSTR: { + /* Add the passed in message to the existing text. Support the + * adding of text that ends in newline. A newline in text + * will force any subsequent text that is added to be added on + * a new output line. + * + * TODO: Text can be added with newlines occurring within the text not + * just at the end. As currently implemented, this can cause + * the text to be rendered such that the text following the + * newline is rendered on a new line. This can cause a poor + * user experience when the user has set only a single text line + * for the message window. In this case, the user will not see + * any line other then the last line of text and the --MORE-- + * message thus missing any text that appears before the last + * embedded newline. This does not meet the requirements of the + * message window. + * This code should be changed to do the right thing and split + * the text so that only lines that end in newlines are added to + * the stored window text. + */ PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam; SCROLLINFO si; char *p; @@ -271,10 +290,17 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) /* check for "--more--" */ if (!data->nevermore && more_prompt_check(hWnd)) { int okkey = 0; - int chop; + char tmptext[MAXWINDOWTEXT + 1]; + // @@@ Ok respnses - /* append more prompt and inticate the update */ + /* save original text */ + strcpy(tmptext, data->window_text[MSG_LINES - 1].text); + + /* text could end in newline so strip it */ + strip_newline(data->window_text[MSG_LINES - 1].text); + + /* append more prompt and indicate the update */ strncat( data->window_text[MSG_LINES - 1].text, MORE, MAXWINDOWTEXT @@ -301,10 +327,9 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) } } - /* erase the "--more--" prompt */ - chop = strlen(data->window_text[MSG_LINES - 1].text) - - strlen(MORE); - data->window_text[MSG_LINES - 1].text[chop] = '\0'; + /* restore original text */ + strcpy(data->window_text[MSG_LINES - 1].text, tmptext); + data->lines_not_seen = 0; } @@ -601,6 +626,7 @@ onPaint(HWND hWnd) - (client_rt.bottom - ps.rcPaint.bottom) / data->yChar); y = min(ps.rcPaint.bottom, client_rt.bottom); for (i = LastLine; i >= FirstLine; i--) { + char tmptext[MAXWINDOWTEXT + 1]; x = data->xChar * (2 - data->xPos); draw_rt.left = x; @@ -612,8 +638,10 @@ onPaint(HWND hWnd) 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)); + /* convert to UNICODE stripping newline */ + strcpy(tmptext, data->window_text[i].text); + strip_newline(tmptext); + NH_A2W(tmptext, wbuf, sizeof(wbuf)); wlen = _tcslen(wbuf); setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn)); #ifdef MSG_WRAP_TEXT @@ -765,6 +793,10 @@ can_append_text(HWND hWnd, int attr, const char *text) if (data->window_text[MSG_LINES - 1].attr != attr) return FALSE; + /* cannot append if current line ends in newline */ + if (str_end_is(data->window_text[MSG_LINES - 1].text, "\n")) + return FALSE; + /* check if the maximum string langth will be exceeded */ if (strlen(data->window_text[MSG_LINES - 1].text) + 2 + /* space characters */ @@ -772,10 +804,11 @@ can_append_text(HWND hWnd, int attr, const char *text) >= MAXWINDOWTEXT) return FALSE; - /* check if the text is goinf to fin into a single line */ + /* check if the text is going to fit into a single line */ strcpy(tmptext, data->window_text[MSG_LINES - 1].text); strcat(tmptext, " "); strcat(tmptext, text); + strip_newline(tmptext); strcat(tmptext, MORE); hdc = GetDC(hWnd); @@ -836,6 +869,8 @@ more_prompt_check(HWND hWnd) hdc, FALSE)); strcpy(tmptext, data->window_text[MSG_LINES - i - 1].text); + strip_newline(tmptext); + if (i == 0) strcat(tmptext, MORE); diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index 680da598e..d1bceaa07 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -36,13 +36,9 @@ mswin_display_splash_window(BOOL show_ver) RECT controlrt; HWND hWnd; int buttop; - int strsize = 0; - int bufsize = BUFSZ; - char *buf = malloc(bufsize); + strbuf_t strbuf; - if (buf == NULL) - panic("out of memory"); - buf[0] = '\0'; + strbuf_init(&strbuf); hWnd = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_SPLASH), GetNHApp()->hMainWnd, NHSplashWndProc); @@ -87,9 +83,9 @@ mswin_display_splash_window(BOOL show_ver) 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, + strbuf_reserve(&strbuf, BUFSIZ); + Sprintf(strbuf.str, "%s\n%s\n%s\n%s\n\n", COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B, COPYRIGHT_BANNER_C, COPYRIGHT_BANNER_D); - strsize = strlen(buf); if (show_ver) { /* Show complete version information */ @@ -98,43 +94,16 @@ mswin_display_splash_window(BOOL show_ver) int verstrsize = 0; getversionstring(verbuf); - verstrsize = strlen(verbuf); - if (verstrsize + strlen("\r\n\r\n") + 1 < BUFSZ - 1) - strcat(verbuf, "\r\n\r\n"); - verstrsize = strlen(verbuf); - - if (strsize + verstrsize + 1 > bufsize) { - bufsize += BUFSZ; - buf = realloc(buf, bufsize); - if (buf == NULL) - panic("out of memory"); - } - strcat(buf, verbuf); - strsize = strlen(buf); + strbuf_append(&strbuf, verbuf); + strbuf_append(&strbuf, "\n\n"); /* 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; - } + while (dlb_fgets(line, LLEN, f)) + strbuf_append(&strbuf, line); (void) dlb_fclose(f); } } else { @@ -147,32 +116,18 @@ mswin_display_splash_window(BOOL show_ver) 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; - } + while (fgets(line, LLEN, nf)) + strbuf_append(&strbuf, line); (void) fclose(nf); } else { - strcat(buf, "No news."); + strbuf_append(&strbuf, "No news."); } } } - SetWindowText(GetDlgItem(hWnd, IDC_EXTRAINFO), buf); - free(buf); + + strbuf_nl_to_crlf(&strbuf); + SetWindowText(GetDlgItem(hWnd, IDC_EXTRAINFO), strbuf.str); + strbuf_empty(&strbuf); ShowWindow(hWnd, SW_SHOW); while (IsWindow(hWnd) && GetMessage(&msg, NULL, 0, 0) != 0) { diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 236396b83..c0cd44f5d 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -75,6 +75,8 @@ COLORREF status_fg_color = RGB(0xFF, 0xFF, 0xFF); COLORREF message_bg_color = RGB(0, 0, 0); COLORREF message_fg_color = RGB(0xFF, 0xFF, 0xFF); +strbuf_t raw_print_strbuf = { 0 }; + /* Interface definition, for windows.c */ struct window_procs mswin_procs = { "MSWIN", @@ -258,8 +260,6 @@ mswin_init_nhwindows(int *argc, char **argv) void mswin_player_selection(void) { - int nRole; - logDebug("mswin_player_selection()\n"); if (iflags.wc_player_selection == VIA_DIALOG) { @@ -309,7 +309,7 @@ mswin_player_selection(void) } } else { /* select a role */ - if (mswin_player_selection_window(&nRole) == IDCANCEL) { + if (!mswin_player_selection_window()) { bail(0); } } @@ -717,8 +717,7 @@ mswin_exit_nhwindows(const char *str) /* Write Window settings to the registry */ mswin_write_reg(); - while (max_brush) - DeleteObject(brush_table[--max_brush]); + } /* Prepare the window to be suspended. */ @@ -1238,6 +1237,7 @@ void mswin_wait_synch() { logDebug("mswin_wait_synch()\n"); + mswin_raw_print_flush(); } /* @@ -1293,6 +1293,40 @@ mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) } } +/* + * mswin_raw_print_accumulate() accumulate the given text into + * raw_print_strbuf. + */ +void +mswin_raw_print_accumulate(const char * str, boolean bold) +{ + bold; // ignored for now + + if (raw_print_strbuf.str != NULL) strbuf_append(&raw_print_strbuf, "\n"); + strbuf_append(&raw_print_strbuf, str); +} + +/* + * mswin_raw_print_flush() - display any text found in raw_print_strbuf in a + * dialog box and clear raw_print_strbuf. + */ +void +mswin_raw_print_flush() +{ + if (raw_print_strbuf.str != NULL) { + int wlen = strlen(raw_print_strbuf.str) + 1; + TCHAR * wbuf = (TCHAR *) alloc(wlen * sizeof(TCHAR)); + if (wbuf != NULL) { + NHMessageBox(GetNHApp()->hMainWnd, + NH_A2W(raw_print_strbuf.str, wbuf, wlen), + MB_ICONINFORMATION | MB_OK); + free(wbuf); + } + strbuf_empty(&raw_print_strbuf); + } +} + + /* raw_print(str) -- Print directly to a screen, or otherwise guarantee that the user sees str. raw_print() appends a newline to str. @@ -1305,14 +1339,12 @@ raw_print(str) -- Print directly to a screen, or otherwise guarantee that 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); + mswin_raw_print_accumulate(str, FALSE); else fprintf(stdout, "%s", str); } @@ -1326,11 +1358,14 @@ 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); + if (str && *str) { + extern int redirect_stdout; + if (!redirect_stdout) + mswin_raw_print_accumulate(str, TRUE); + else + fprintf(stdout, "%s", str); + } } /* diff --git a/win/win32/resource.h b/win/win32/resource.h index 98b6ba1b8..899007b9f 100644 --- a/win/win32/resource.h +++ b/win/win32/resource.h @@ -2,155 +2,155 @@ // 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 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_RANDOM 1315 +#define IDC_ABOUT_VERSION 1327 +#define IDC_ABOUT_COPYRIGHT 1328 +#define IDC_EXTRAINFO 1331 +#define IDC_PLSEL_ROLE_LIST 1332 +#define IDC_PLSEL_RACE_LIST 1333 +#define IDC_PLSEL_ALIGN_LAWFUL 1334 +#define IDC_PLSEL_ALIGN_NEUTRAL 1335 +#define IDC_PLSEL_ALIGN_CHAOTIC 1336 +#define IDC_PLSEL_GENDER_MALE 1337 +#define IDC_PLSEL_GENDER_FEMALE 1338 +#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 +#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 +#define _APS_NEXT_RESOURCE_VALUE 146 +#define _APS_NEXT_COMMAND_VALUE 32800 +#define _APS_NEXT_CONTROL_VALUE 1341 +#define _APS_NEXT_SYMED_VALUE 110 #endif #endif diff --git a/win/win32/winMS.h b/win/win32/winMS.h index b799da1e7..c5ee77368 100644 --- a/win/win32/winMS.h +++ b/win/win32/winMS.h @@ -29,6 +29,7 @@ #define WIN32_LEAN_AND_MEAN #include +#include #include #include #include "hack.h" @@ -164,6 +165,7 @@ 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); +void mswin_raw_print_flush(); int mswin_nhgetch(void); int mswin_nh_poskey(int *x, int *y, int *mod); void mswin_nhbell(void); diff --git a/win/win32/winhack.rc b/win/win32/winhack.rc index 4c69358c9..06876aecf 100644 --- a/win/win32/winhack.rc +++ b/win/win32/winhack.rc @@ -1,4 +1,4 @@ -//Microsoft Developer Studio generated resource script. +// Microsoft Visual C++ generated resource script. // #include "resource.h" @@ -19,13 +19,11 @@ LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources +// English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) -#endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // @@ -34,14 +32,15 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -IDI_NETHACKW ICON DISCARDABLE "NETHACK.ICO" +IDI_NETHACKW ICON "NETHACK.ICO" + ///////////////////////////////////////////////////////////////////////////// // // Menu // -IDC_NETHACKW MENU DISCARDABLE +IDC_NETHACKW MENU BEGIN POPUP "&File" BEGIN @@ -98,7 +97,7 @@ END // Accelerator // -IDC_NETHACKW ACCELERATORS MOVEABLE PURE +IDC_NETHACKW ACCELERATORS BEGIN "?", IDM_ABOUT, ASCII, ALT "/", IDM_ABOUT, ASCII, ALT @@ -110,8 +109,8 @@ END // Dialog // -IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +IDD_ABOUTBOX DIALOG 22, 17, 230, 75 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "System" BEGIN @@ -121,29 +120,27 @@ BEGIN END IDD_NHTEXT DIALOGEX 0, 0, 172, 178 -STYLE WS_CHILD | WS_CLIPSIBLINGS | WS_THICKFRAME +STYLE DS_SETFONT | WS_CHILD | WS_CLIPSIBLINGS | WS_THICKFRAME EXSTYLE WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT -FONT 8, "MS Sans Serif", 0, 0 +FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN - EDITTEXT IDC_TEXT_CONTROL,0,0,172,160,ES_MULTILINE | - ES_OEMCONVERT | ES_READONLY | WS_VSCROLL | WS_HSCROLL | NOT WS_TABSTOP + 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 +STYLE DS_SETFONT | WS_CHILD | WS_CLIPSIBLINGS | WS_THICKFRAME EXSTYLE WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT -FONT 8, "MS Sans Serif", 0, 0 +FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN LISTBOX IDC_MENU_LIST,10,10,170,55,LBS_SORT | NOT WS_BORDER - EDITTEXT IDC_MENU_TEXT,10,70,170,60,ES_MULTILINE | ES_OEMCONVERT | - ES_READONLY | WS_VSCROLL | WS_HSCROLL | NOT WS_TABSTOP | NOT WS_BORDER + EDITTEXT IDC_MENU_TEXT,10,70,170,60,ES_MULTILINE | ES_OEMCONVERT | ES_READONLY | NOT WS_BORDER | 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 +IDD_GETLIN DIALOG 0, 0, 131, 29 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Question?" FONT 8, "MS Sans Serif" BEGIN @@ -152,65 +149,54 @@ BEGIN 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 +IDD_EXTCMD DIALOG 0, 0, 137, 117 +STYLE DS_SETFONT | 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 + 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 +IDD_PLAYER_SELECTOR DIALOGEX 0, 0, 225, 212 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "What are you?" -FONT 8, "MS Sans Serif" +FONT 8, "MS Sans Serif", 0, 0, 0x0 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 + DEFPUSHBUTTON "Play",IDOK,12,192,54,14,WS_GROUP + PUSHBUTTON "Quit",IDCANCEL,162,192,54,14,WS_GROUP + EDITTEXT IDC_PLSEL_NAME,12,12,105,12,ES_AUTOHSCROLL | ES_READONLY | WS_GROUP | NOT WS_TABSTOP + CONTROL "Neutral",IDC_PLSEL_ALIGN_NEUTRAL,"Button",BS_AUTORADIOBUTTON,168,60,37,10 + CONTROL "Lawful",IDC_PLSEL_ALIGN_LAWFUL,"Button",BS_AUTORADIOBUTTON | WS_GROUP,168,48,35,10 + CONTROL "Chaotic",IDC_PLSEL_ALIGN_CHAOTIC,"Button",BS_AUTORADIOBUTTON,168,72,38,10 + CONTROL "Male",IDC_PLSEL_GENDER_MALE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,168,108,30,10 + CONTROL "Female",IDC_PLSEL_GENDER_FEMALE,"Button",BS_AUTORADIOBUTTON,168,120,38,10 + GROUPBOX "Alignment",IDC_STATIC,162,36,48,54 + GROUPBOX "Gender",IDC_STATIC,162,96,48,42 + GROUPBOX "Role",IDC_STATIC,6,36,72,150 + GROUPBOX "Race",IDC_STATIC,84,36,72,72 + PUSHBUTTON "Random",IDC_PLSEL_RANDOM,90,192,54,14,WS_GROUP + GROUPBOX "Name",IDC_STATIC,6,0,120,30 + CONTROL "",IDC_PLSEL_ROLE_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_OWNERDRAWFIXED | LVS_ALIGNLEFT | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_GROUP | WS_TABSTOP,12,48,60,130 + CONTROL "",IDC_PLSEL_RACE_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_OWNERDRAWFIXED | LVS_ALIGNLEFT | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_GROUP | WS_TABSTOP,90,48,60,51 END IDD_NHRIP DIALOGEX 0, 0, 281, 209 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Here lies..." -FONT 8, "MS Sans Serif", 0, 0 +FONT 8, "MS Sans Serif", 0, 0, 0x1 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 +IDD_SPLASH DIALOG 0, 0, 281, 257 +STYLE DS_SETFONT | 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 + EDITTEXT IDC_EXTRAINFO,7,176,267,52,ES_MULTILINE | ES_READONLY | WS_VSCROLL END @@ -220,7 +206,7 @@ END // TEXTINCLUDE // -2 TEXTINCLUDE DISCARDABLE +2 TEXTINCLUDE BEGIN "#if defined(__BORLANDC__)\r\n" "LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US\r\n" @@ -232,13 +218,13 @@ BEGIN "\0" END -3 TEXTINCLUDE DISCARDABLE +3 TEXTINCLUDE BEGIN "\r\n" "\0" END -1 TEXTINCLUDE DISCARDABLE +1 TEXTINCLUDE BEGIN "resource.h\0" END @@ -251,14 +237,22 @@ END // 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" +IDB_TILES BITMAP "tiles.bmp" + +IDB_MENU_SEL BITMAP "mnsel.bmp" + +IDB_MENU_UNSEL BITMAP "mnunsel.bmp" + +IDB_PETMARK BITMAP "petmark.bmp" + +IDB_PILEMARK BITMAP "pilemark.bmp" + +IDB_MENU_SEL_COUNT BITMAP "mnselcnt.bmp" + +IDB_RIP BITMAP "rip.bmp" + +IDB_SPLASH BITMAP "splash.bmp" + ///////////////////////////////////////////////////////////////////////////// // @@ -266,7 +260,7 @@ IDB_SPLASH BITMAP DISCARDABLE "splash.bmp" // #ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO DISCARDABLE +GUIDELINES DESIGNINFO BEGIN IDD_NHTEXT, DIALOG BEGIN @@ -297,9 +291,9 @@ BEGIN IDD_PLAYER_SELECTOR, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 145 + RIGHTMARGIN, 218 TOPMARGIN, 7 - BOTTOMMARGIN, 162 + BOTTOMMARGIN, 205 END IDD_NHRIP, DIALOG @@ -342,14 +336,14 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "FileDescription", "NetHack for Windows - Graphical Interface\0" - VALUE "FileVersion", "3.6.1\0" - VALUE "InternalName", "NetHackW\0" - VALUE "LegalCopyright", "Copyright (C) 1985 - 2017. 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.6.1\0" + VALUE "FileDescription", "NetHack for Windows - Graphical Interface" + VALUE "FileVersion", "3.6.1" + VALUE "InternalName", "NetHackW" + VALUE "LegalCopyright", "Copyright (C) 1985 - 2017. By Stichting Mathematisch Centrum and M. Stephenson. See license for details." + VALUE "OriginalFilename", "NetHackW.exe" + VALUE "PrivateBuild", "140606" + VALUE "ProductName", "NetHack" + VALUE "ProductVersion", "3.6.1" END END BLOCK "VarFileInfo" @@ -358,19 +352,31 @@ BEGIN END END + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_PLAYER_SELECTOR AFX_DIALOG_LAYOUT +BEGIN + 0 +END + + ///////////////////////////////////////////////////////////////////////////// // // String Table // -STRINGTABLE DISCARDABLE +STRINGTABLE 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 +#endif // English (United States) resources /////////////////////////////////////////////////////////////////////////////