Compare commits

..

15 Commits

@ -1 +1,4 @@
111 whatever you do
wherever you gou
i am always here
waitting for you

@ -1,3 +1,4 @@
//2023/12/3 wh
/* NetHack 3.7 alloc.c $NHDT-Date: 1687343500 2023/06/21 10:31:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.31 $ */ /* NetHack 3.7 alloc.c $NHDT-Date: 1687343500 2023/06/21 10:31:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.31 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */
@ -122,16 +123,17 @@ static int ptrbufidx = 0;
char * char *
fmt_ptr(const genericptr ptr) fmt_ptr(const genericptr ptr)
{ {
char *buf; char *buf; // Declare a character pointer variable buf
buf = ptrbuf[ptrbufidx]; buf = ptrbuf[ptrbufidx]; // Point buf to the element at index ptrbufidx in the ptrbuf array
if (++ptrbufidx >= PTRBUFCNT) if (++ptrbufidx >= PTRBUFCNT) // If ptrbufidx exceeds the range of PTRBUFCNT after incrementing
ptrbufidx = 0; ptrbufidx = 0; // Reset ptrbufidx to 0
Sprintf(buf, PTR_FMT, (PTR_TYP) ptr); Sprintf(buf, PTR_FMT, (PTR_TYP) ptr); // Use the Sprintf function to format the pointer value into a string and store it in buf
return buf; return buf; // Return the formatted string
} }
#ifdef MONITOR_HEAP #ifdef MONITOR_HEAP
/* If ${NH_HEAPLOG} is defined and we can create a file by that name, /* If ${NH_HEAPLOG} is defined and we can create a file by that name,
@ -231,42 +233,42 @@ nhdupstr(const char *string, const char *file, int line)
char * char *
dupstr(const char *string) dupstr(const char *string)
{ {
unsigned len = FITSuint_(strlen(string), __func__, (int) __LINE__); unsigned len = FITSuint_(strlen(string), __func__, (int) __LINE__); // Get the length of the input string using strlen() function, and store it in the variable len
return strcpy((char *) alloc(len + 1), string); return strcpy((char *) alloc(len + 1), string); // Allocate memory for a new string of length len+1, and copy the input string into the newly allocated memory
} }
/* similar for reasonable size strings, but return length of input as well */ /* similar for reasonable size strings, but return length of input as well */
char * char *
dupstr_n(const char *string, unsigned int *lenout) dupstr_n(const char *string, unsigned int *lenout)
{ {
size_t len = strlen(string); size_t len = strlen(string); // Get the length of the input string using strlen() function
if (len >= LARGEST_INT) if (len >= LARGEST_INT) // If the length exceeds a predefined constant LARGEST_INT, which represents the maximum length allowed
panic("string too long"); panic("string too long"); // Raise an error or handle the situation when the string is too long
*lenout = (unsigned int) len; *lenout = (unsigned int) len; // Store the length of the input string in the variable lenout
return strcpy((char *) alloc(len + 1), string); return strcpy((char *) alloc(len + 1), string); // Allocate memory for a new string of length len+1, copy the input string into the newly allocated memory, and return the new string
} }
/* cast to int or panic on overflow; use via macro */ /* cast to int or panic on overflow; use via macro */
int int
FITSint_(LUA_INTEGER i, const char *file, int line) FITSint_(LUA_INTEGER i, const char *file, int line)
{ {
int iret = (int) i; int iret = (int) i; // Cast the input parameter i to int type and store it in the variable iret
if (iret != i) if (iret != i) // If the casted value is not equal to the original input value
panic("Overflow at %s:%d", file, line); panic("Overflow at %s:%d", file, line); // Raise an error or handle the situation when overflow occurs
return iret; return iret; // Return the casted int value
} }
unsigned unsigned
FITSuint_(unsigned long long ull, const char *file, int line) FITSuint_(unsigned long long ull, const char *file, int line)
{ {
unsigned uret = (unsigned) ull; unsigned uret = (unsigned) ull; // Cast the input parameter ull to unsigned type and store it in the variable uret
if (uret != ull) if (uret != ull) // If the casted value is not equal to the original input value
panic("Overflow at %s:%d", file, line); panic("Overflow at %s:%d", file, line); // Raise an error or handle the situation when overflow occurs
return uret; return uret; // Return the casted unsigned value
} }
/*alloc.c*/ /*alloc.c*/

@ -1,3 +1,4 @@
//2023/23/3 wh
/* NetHack 3.7 apply.c $NHDT-Date: 1695159606 2023/09/19 21:40:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.422 $ */ /* NetHack 3.7 apply.c $NHDT-Date: 1695159606 2023/09/19 21:40:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.422 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */
@ -97,18 +98,18 @@ use_camera(struct obj *obj)
static int static int
use_towel(struct obj *obj) use_towel(struct obj *obj)
{ {
boolean drying_feedback = (obj == uwep); boolean drying_feedback = (obj == uwep); // Check if the object being used is the player's wielded weapon
if (!freehand()) { if (!freehand()) { // If the player doesn't have a free hand
You("have no free %s!", body_part(HAND)); You("have no free %s!", body_part(HAND)); // Display a message indicating that the player has no free hand
return ECMD_OK; return ECMD_OK; // Return with the result code ECMD_OK to indicate successful execution
} else if (obj == ublindf) { } else if (obj == ublindf) { // If the object being used is the player's blindfold
You("cannot use it while you're wearing it!"); You("cannot use it while you're wearing it!"); // Display a message indicating that the player cannot use the blindfold while wearing it
return ECMD_OK; return ECMD_OK; // Return with the result code ECMD_OK to indicate successful execution
} else if (obj->cursed) { } else if (obj->cursed) { // If the object being used is cursed
long old; long old;
switch (rn2(3)) { switch (rn2(3)) { // Randomly choose one of three cases
case 2: case 2:
old = (Glib & TIMEOUT); old = (Glib & TIMEOUT);
make_glib((int) old + rn1(10, 3)); /* + 3..12 */ make_glib((int) old + rn1(10, 3)); /* + 3..12 */
@ -116,7 +117,7 @@ use_towel(struct obj *obj)
(old ? "are filthier than ever" : "get slimy")); (old ? "are filthier than ever" : "get slimy"));
if (is_wet_towel(obj)) if (is_wet_towel(obj))
dry_a_towel(obj, -1, drying_feedback); dry_a_towel(obj, -1, drying_feedback);
return ECMD_TIME; return ECMD_TIME; // Return with the result code ECMD_TIME to indicate that time has passed
case 1: case 1:
if (!ublindf) { if (!ublindf) {
old = u.ucreamed; old = u.ucreamed;
@ -143,20 +144,20 @@ use_towel(struct obj *obj)
} }
if (is_wet_towel(obj)) if (is_wet_towel(obj))
dry_a_towel(obj, -1, drying_feedback); dry_a_towel(obj, -1, drying_feedback);
return ECMD_TIME; return ECMD_TIME; // Return with the result code ECMD_TIME to indicate that time has passed
case 0: case 0:
break; break;
} }
} }
if (Glib) { if (Glib) { // If the player's hands are slippery
make_glib(0); make_glib(0); // Remove slipperiness from the player's hands
You("wipe off your %s.", You("wipe off your %s.",
!uarmg ? makeplural(body_part(HAND)) : gloves_simple_name(uarmg)); !uarmg ? makeplural(body_part(HAND)) : gloves_simple_name(uarmg));
if (is_wet_towel(obj)) if (is_wet_towel(obj))
dry_a_towel(obj, -1, drying_feedback); dry_a_towel(obj, -1, drying_feedback);
return ECMD_TIME; return ECMD_TIME; // Return with the result code ECMD_TIME to indicate that time has passed
} else if (u.ucreamed) { } else if (u.ucreamed) { // If the player's face is creamed
incr_itimeout(&HBlinded, (-1 * (int) u.ucreamed)); incr_itimeout(&HBlinded, (-1 * (int) u.ucreamed));
u.ucreamed = 0; u.ucreamed = 0;
if (!Blinded) { if (!Blinded) {
@ -170,13 +171,13 @@ use_towel(struct obj *obj)
} }
if (is_wet_towel(obj)) if (is_wet_towel(obj))
dry_a_towel(obj, -1, drying_feedback); dry_a_towel(obj, -1, drying_feedback);
return ECMD_TIME; return ECMD_TIME; // Return with the result code ECMD_TIME to indicate that time has passed
} }
Your("%s and %s are already clean.", body_part(FACE), Your("%s and %s are already clean.", body_part(FACE),
makeplural(body_part(HAND))); makeplural(body_part(HAND)));
return ECMD_OK; return ECMD_OK; // Return with the result code ECMD_OK to indicate successful execution
} }
/* maybe give a stethoscope message based on floor objects */ /* maybe give a stethoscope message based on floor objects */

@ -2,7 +2,7 @@
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
#include "hack.h" #include "hack.h"
#include "artifact.h" #include "artifact.h"
#include "artilist.h" #include "artilist.h"

@ -19,25 +19,34 @@ static int bcrestriction = 0;
static struct breadcrumbs bcpbreadcrumbs = {0}, bcubreadcrumbs = {0}; static struct breadcrumbs bcpbreadcrumbs = {0}, bcubreadcrumbs = {0};
#endif #endif
void void ballrelease(boolean showmsg)
ballrelease(boolean showmsg)
{ {
if (carried(uball) && !welded(uball)) { if (carried(uball) && !welded(uball)) {
// 如果玩家正在携带铁球并且未被焊接
if (showmsg) if (showmsg)
pline("Startled, you drop the iron ball."); pline("Startled, you drop the iron ball.");
// 如果需要显示消息,打印提示信息"Startled, you drop the iron ball."
// 移除铁球作为武器、备用武器或弹药
if (uwep == uball) if (uwep == uball)
setuwep((struct obj *) 0); setuwep((struct obj *) 0);
// 如果当前武器是铁球,将当前武器设为无
if (uswapwep == uball) if (uswapwep == uball)
setuswapwep((struct obj *) 0); setuswapwep((struct obj *) 0);
// 如果备用武器是铁球,将备用武器设为无
if (uquiver == uball) if (uquiver == uball)
setuqwep((struct obj *) 0); setuqwep((struct obj *) 0);
/* [this used to test 'if (uwep != uball)' but that always passes // 如果弹药是铁球,将弹药设为无
after the setuwep() above] */
freeinv(uball); /* remove from inventory but don't place on floor */ // 从物品栏中移除铁球,但不放置到地面上
freeinv(uball);
// 更新负重状态并显示相关信息
(void) encumber_msg(); (void) encumber_msg();
} }
} }
/* ball&chain might hit hero when falling through a trap door */ /* ball&chain might hit hero when falling through a trap door */
void void
ballfall(void) ballfall(void)
@ -176,16 +185,20 @@ unplacebc_core(void)
u.bc_felt = 0; /* feel nothing */ u.bc_felt = 0; /* feel nothing */
} }
static boolean static boolean check_restriction(int restriction)
check_restriction(int restriction)
{ {
boolean ret = FALSE; boolean ret = FALSE;
// 检查是否没有限制或者当前限制与覆盖限制相同
if (!bcrestriction || (restriction == override_restriction)) if (!bcrestriction || (restriction == override_restriction))
ret = TRUE; ret = TRUE;
// 如果满足条件则设置返回值为TRUE
else else
ret = (bcrestriction == restriction) ? TRUE : FALSE; ret = (bcrestriction == restriction) ? TRUE : FALSE;
// 否则检查当前限制是否与传入的限制相同并设置返回值为TRUE或者FALSE
return ret; return ret;
// 返回结果
} }
#ifndef BREADCRUMBS #ifndef BREADCRUMBS
@ -283,22 +296,28 @@ Placebc(const char *funcnm, int linenum)
placebc_core(); placebc_core();
} }
void void Unplacebc(const char *funcnm, int linenum)
Unplacebc(const char *funcnm, int linenum)
{ {
// 如果存在限制
if (bcrestriction) { if (bcrestriction) {
char panicbuf[BUFSZ]; char panicbuf[BUFSZ];
// 创建错误消息字符串
Sprintf(panicbuf, "Unplacebc from %s:%d, when restricted to %s:%d", Sprintf(panicbuf, "Unplacebc from %s:%d, when restricted to %s:%d",
funcnm, linenum, funcnm, linenum,
bcubreadcrumbs.funcnm, bcubreadcrumbs.linenum); bcubreadcrumbs.funcnm, bcubreadcrumbs.linenum);
// 将错误消息记录到日志中
paniclog("Unplacebc", panicbuf); paniclog("Unplacebc", panicbuf);
} }
// 禁用当前限制,启用上一个限制,并更新函数名和行号
bcpbreadcrumbs.in_effect = FALSE; bcpbreadcrumbs.in_effect = FALSE;
bcubreadcrumbs.in_effect = TRUE; bcubreadcrumbs.in_effect = TRUE;
bcubreadcrumbs.funcnm = funcnm; bcubreadcrumbs.funcnm = funcnm;
bcubreadcrumbs.linenum = linenum; bcubreadcrumbs.linenum = linenum;
// 执行unplacebc_core函数
unplacebc_core(); unplacebc_core();
} }

@ -17,18 +17,22 @@ no_bones_level(d_level *lev)
{ {
s_level *sptr; s_level *sptr;
// 如果当前d_level不是gs.save_dlevel则将当前d_level赋值为gs.save_dlevel
if (ledger_no(&gs.save_dlevel)) if (ledger_no(&gs.save_dlevel))
assign_level(lev, &gs.save_dlevel); assign_level(lev, &gs.save_dlevel);
return (boolean) (((sptr = Is_special(lev)) != 0 && !sptr->boneid) // 满足以下条件时返回True表示该层不能生成骨堆
|| !gd.dungeons[lev->dnum].boneid return (boolean) (
/* no bones on the last or multiway branch levels // 1. 该层是特殊层并且没有设置骨堆id
in any dungeon (level 1 isn't multiway) */ ((sptr = Is_special(lev)) != 0 && !sptr->boneid)
|| Is_botlevel(lev) // 2. 该层所在的地牢中没有设置骨堆id
|| (Is_branchlev(lev) && lev->dlevel > 1) || !gd.dungeons[lev->dnum].boneid
/* no bones in the invocation level */ // 3. 该层是地牢中的最后一层或多路分支的末端层(除了第一层)
|| (In_hell(lev) || Is_botlevel(lev)
&& lev->dlevel == dunlevs_in_dungeon(lev) - 1)); || (Is_branchlev(lev) && lev->dlevel > 1)
// 4. 该层是地狱入口
|| (In_hell(lev) && lev->dlevel == dunlevs_in_dungeon(lev) - 1)
);
} }
/* Call this function for each fruit object saved in the bones level: it marks /* Call this function for each fruit object saved in the bones level: it marks
@ -195,6 +199,7 @@ void
sanitize_name(char *namebuf) sanitize_name(char *namebuf)
{ {
int c; int c;
// 是否在终端窗口下且终端不支持8位字符集
boolean strip_8th_bit = (WINDOWPORT(tty) boolean strip_8th_bit = (WINDOWPORT(tty)
&& !iflags.wc_eight_bit_input); && !iflags.wc_eight_bit_input);
@ -202,13 +207,16 @@ sanitize_name(char *namebuf)
only the current player could have left these bones--except only the current player could have left these bones--except
things like "hearse" and other bones exchange schemes make things like "hearse" and other bones exchange schemes make
that assumption false */ that assumption false */
// 遍历字符串中的每个字符,进行处理
while (*namebuf) { while (*namebuf) {
// 将字符转换为7位ASCII码值
c = *namebuf & 0177; c = *namebuf & 0177;
if (c < ' ' || c == '\177') { if (c < ' ' || c == '\177') {
/* non-printable or undesirable */ /* 非可打印字符或不需要的字符,用'.'代替 */
*namebuf = '.'; *namebuf = '.';
} else if (c != *namebuf) { } else if (c != *namebuf) {
/* expected to be printable if user wants such things */ /* 如果字符不是可打印字符且用户希望看到可打印字符时,则用'_'代替 */
if (strip_8th_bit) if (strip_8th_bit)
*namebuf = '_'; *namebuf = '_';
} }
@ -216,6 +224,7 @@ sanitize_name(char *namebuf)
} }
} }
/* Give object to a random object-liking monster on or adjacent to x,y /* Give object to a random object-liking monster on or adjacent to x,y
but skipping hero's location. but skipping hero's location.
If no such monster, place object on floor at x,y. */ If no such monster, place object on floor at x,y. */
@ -388,11 +397,15 @@ remove_mon_from_bones(struct monst *mtmp)
{ {
struct permonst *mptr = mtmp->data; struct permonst *mptr = mtmp->data;
// If the monster is the Wizard, Medusa, or has specific monster sounds,
// or is Vlad, or is the Oracle (with specific condition), remove it from bones.
if (mtmp->iswiz || mptr == &mons[PM_MEDUSA] if (mtmp->iswiz || mptr == &mons[PM_MEDUSA]
|| mptr->msound == MS_NEMESIS || mptr->msound == MS_LEADER || mptr->msound == MS_NEMESIS || mptr->msound == MS_LEADER
|| is_Vlad(mtmp) /* mptr == &mons[VLAD_THE_IMPALER] || cham == VLAD */ || is_Vlad(mtmp) /* mptr == &mons[VLAD_THE_IMPALER] || cham == VLAD */
|| (mptr == &mons[PM_ORACLE] && !fixuporacle(mtmp))) || (mptr == &mons[PM_ORACLE] && !fixuporacle(mtmp)))
{
mongone(mtmp); mongone(mtmp);
}
} }
/* save bones and possessions of a deceased adventurer */ /* save bones and possessions of a deceased adventurer */

@ -1,3 +1,4 @@
//2023/12/3 wh
/* NetHack 3.7 dbridge.c $NHDT-Date: 1596498153 2020/08/03 23:42:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.47 $ */ /* NetHack 3.7 dbridge.c $NHDT-Date: 1596498153 2020/08/03 23:42:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.47 $ */
/* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1989 by Jean-Christophe Collet */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@ -58,72 +59,67 @@ is_pool(coordxy x, coordxy y)
return FALSE; return FALSE;
} }
boolean boolean is_lava(coordxy x, coordxy y)
is_lava(coordxy x, coordxy y)
{ {
schar ltyp; schar ltyp;
if (!isok(x, y)) if (!isok(x, y)) // If the coordinates are not within the game map
return FALSE; return FALSE; // Return FALSE to indicate that it is not lava
ltyp = levl[x][y].typ; ltyp = levl[x][y].typ; // Get the terrain type at the coordinates
if (ltyp == LAVAPOOL || ltyp == LAVAWALL if (ltyp == LAVAPOOL || ltyp == LAVAWALL
|| (ltyp == DRAWBRIDGE_UP || (ltyp == DRAWBRIDGE_UP
&& (levl[x][y].drawbridgemask & DB_UNDER) == DB_LAVA)) && (levl[x][y].drawbridgemask & DB_UNDER) == DB_LAVA))
return TRUE; return TRUE; // Return TRUE if the terrain type is lava or a drawbridge over lava
return FALSE; return FALSE; // Otherwise, return FALSE
} }
boolean boolean is_pool_or_lava(coordxy x, coordxy y)
is_pool_or_lava(coordxy x, coordxy y)
{ {
if (is_pool(x, y) || is_lava(x, y)) if (is_pool(x, y) || is_lava(x, y))
return TRUE; return TRUE; // Return TRUE if the location is a pool or lava
else else
return FALSE; return FALSE; // Otherwise, return FALSE
} }
boolean boolean is_ice(coordxy x, coordxy y)
is_ice(coordxy x, coordxy y)
{ {
schar ltyp; schar ltyp;
if (!isok(x, y)) if (!isok(x, y)) // If the coordinates are not within the game map
return FALSE; return FALSE; // Return FALSE to indicate that it is not ice
ltyp = levl[x][y].typ; ltyp = levl[x][y].typ; // Get the terrain type at the coordinates
if (ltyp == ICE || (ltyp == DRAWBRIDGE_UP if (ltyp == ICE || (ltyp == DRAWBRIDGE_UP
&& (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE)) && (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE))
return TRUE; return TRUE; // Return TRUE if the terrain type is ice or a drawbridge over ice
return FALSE; return FALSE; // Otherwise, return FALSE
} }
boolean boolean is_moat(coordxy x, coordxy y)
is_moat(coordxy x, coordxy y)
{ {
schar ltyp; schar ltyp;
if (!isok(x, y)) if (!isok(x, y)) // If the coordinates are not within the game map
return FALSE; return FALSE; // Return FALSE to indicate that it is not a moat
ltyp = levl[x][y].typ; ltyp = levl[x][y].typ; // Get the terrain type at the coordinates
if (!Is_juiblex_level(&u.uz) if (!Is_juiblex_level(&u.uz)
&& (ltyp == MOAT && (ltyp == MOAT
|| (ltyp == DRAWBRIDGE_UP || (ltyp == DRAWBRIDGE_UP
&& (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT))) && (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT)))
return TRUE; return TRUE; // Return TRUE if the terrain type is a moat or a drawbridge over a moat (excluding Juiblex's level)
return FALSE; return FALSE; // Otherwise, return FALSE
} }
schar schar db_under_typ(int mask)
db_under_typ(int mask)
{ {
switch (mask & DB_UNDER) { switch (mask & DB_UNDER) {
case DB_ICE: case DB_ICE:
return ICE; return ICE; // Return the terrain type as ice if the mask corresponds to ice
case DB_LAVA: case DB_LAVA:
return LAVAPOOL; return LAVAPOOL; // Return the terrain type as lava if the mask corresponds to lava
case DB_MOAT: case DB_MOAT:
return MOAT; return MOAT; // Return the terrain type as a moat if the mask corresponds to a moat
default: default:
return STONE; return STONE; // Return the terrain type as stone for other cases
} }
} }

@ -17,7 +17,7 @@ NEARDATA const struct c_color_names c_color_names = {
"black", "amber", "golden", "light blue", "red", "green", "black", "amber", "golden", "light blue", "red", "green",
"silver", "blue", "purple", "white", "orange" "silver", "blue", "purple", "white", "orange"
}; };
const char *c_obj_colors[] = { //这里定义了一些物品的颜色 const char *c_obj_colors[] = {
"black", /* CLR_BLACK */ "black", /* CLR_BLACK */
"red", /* CLR_RED */ "red", /* CLR_RED */
"green", /* CLR_GREEN */ "green", /* CLR_GREEN */
@ -36,8 +36,8 @@ const char *c_obj_colors[] = { //这里定义了一些物品的颜色
"white", /* CLR_WHITE */ "white", /* CLR_WHITE */
}; };
const struct c_common_strings c_common_strings = //结构体变量中包含了一些常见的字符串,用于文本输出 const struct c_common_strings c_common_strings =
{ "Nothing happens.", //在游戏中提供反馈、描述情况,进行交互 { "Nothing happens.",
"That's enough tries!", "That's enough tries!",
"That is a silly thing to %s.", "That is a silly thing to %s.",
"shudder for a moment.", "shudder for a moment.",
@ -50,34 +50,33 @@ const struct c_common_strings c_common_strings = //结构体变量中包含了
{ "mon", "you" } { "mon", "you" }
}; };
const struct savefile_info default_sfinfo = { //定义了保存文件的默认信息 const struct savefile_info default_sfinfo = {
#ifdef NHSTDC //用于保存文件格式的标志位 #ifdef NHSTDC
0x00000000UL 0x00000000UL
#else #else
0x00000000L 0x00000000L
#endif #endif
#if defined(COMPRESS) || defined(ZLIB_COMP) //用于外部压缩标志位 #if defined(COMPRESS) || defined(ZLIB_COMP)
| SFI1_EXTERNALCOMP | SFI1_EXTERNALCOMP
#endif #endif
#if defined(ZEROCOMP) #if defined(ZEROCOMP)
| SFI1_ZEROCOMP //零压缩标志位 | SFI1_ZEROCOMP
#endif #endif
#if defined(RLECOMP) #if defined(RLECOMP)
| SFI1_RLECOMP //RLE压缩标志 | SFI1_RLECOMP
#endif #endif
, ,
#ifdef NHSTDC #ifdef NHSTDC
0x00000000UL, 0x00000000UL //保留字段 0x00000000UL, 0x00000000UL
#else #else
0x00000000L, 0x00000000L 0x00000000L, 0x00000000L
#endif #endif
}; };
const char disclosure_options[] = "iavgco"; //是一个字符数组,包含了几个选项。这些选项用于控制信息的披露程度。 const char disclosure_options[] = "iavgco";
char emptystr[] = {0}; /* non-const */ //是一个字符数组,用于表示空字符串。它是非常量数组,可以被修改。 char emptystr[] = {0}; /* non-const */
NEARDATA struct flag flags; /* extern declaration is in flag.h, not decl.h */ NEARDATA struct flag flags; /* extern declaration is in flag.h, not decl.h */
//是一个结构体变量用于存储游戏中的标志位。该变量在flag.h中有外部声明。
/* Global windowing data, defined here for multi-window-system support */ /* Global windowing data, defined here for multi-window-system support */
#ifdef WIN32 #ifdef WIN32
@ -85,28 +84,25 @@ boolean fqn_prefix_locked[PREFIX_COUNT] = { FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE }; FALSE };
//是一个布尔数组用于表示文件名前缀是否被锁定。在这段代码中它被初始化为全为FALSE。
#endif #endif
#ifdef PREFIXES_IN_USE #ifdef PREFIXES_IN_USE
const char *fqn_prefix_names[PREFIX_COUNT] = { const char *fqn_prefix_names[PREFIX_COUNT] = {
"hackdir", "leveldir", "savedir", "bonesdir", "datadir", "hackdir", "leveldir", "savedir", "bonesdir", "datadir",
"scoredir", "lockdir", "sysconfdir", "configdir", "troubledir" "scoredir", "lockdir", "sysconfdir", "configdir", "troubledir"
};//是一个字符串指针数组,包含了一些文件名前缀的名称。这些名称用于指定不同类型文件的存储路径。 };
#endif #endif
/* x/y/z deltas for the 10 movement directions (8 compass pts, 2 down/up) */ /* x/y/z deltas for the 10 movement directions (8 compass pts, 2 down/up) */
const schar xdir[N_DIRS_Z] = { -1, -1, 0, 1, 1, 1, 0, -1, 0, 0 }; const schar xdir[N_DIRS_Z] = { -1, -1, 0, 1, 1, 1, 0, -1, 0, 0 };
const schar ydir[N_DIRS_Z] = { 0, -1, -1, -1, 0, 1, 1, 1, 0, 0 }; const schar ydir[N_DIRS_Z] = { 0, -1, -1, -1, 0, 1, 1, 1, 0, 0 };
const schar zdir[N_DIRS_Z] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, -1 }; const schar zdir[N_DIRS_Z] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, -1 };
//是三个有符号字符数组分别表示十个移动方向包括八个主要方向和上下方向的x、y和z轴的增量。
/* redordered directions, cardinals first */ /* redordered directions, cardinals first */
const schar dirs_ord[N_DIRS] = const schar dirs_ord[N_DIRS] =
{ DIR_W, DIR_N, DIR_E, DIR_S, DIR_NW, DIR_NE, DIR_SE, DIR_SW }; { DIR_W, DIR_N, DIR_E, DIR_S, DIR_NW, DIR_NE, DIR_SE, DIR_SW };
//是一个有符号字符数组,表示经过重新排序的移动方向。首先是四个基本方向,然后是四个对角线方向。
NEARDATA boolean has_strong_rngseed = FALSE; //是一个布尔变量,用于表示是否具有强随机种子。 NEARDATA boolean has_strong_rngseed = FALSE;
struct engr *head_engr; struct engr *head_engr;
NEARDATA struct instance_flags iflags; //是一个结构体变量,用于存储游戏实例的标志位。 NEARDATA struct instance_flags iflags;
/* NOTE: the order of these words exactly corresponds to the /* NOTE: the order of these words exactly corresponds to the
order of oc_material values #define'd in objclass.h. */ order of oc_material values #define'd in objclass.h. */
const char *materialnm[] = { "mysterious", "liquid", "wax", "organic", const char *materialnm[] = { "mysterious", "liquid", "wax", "organic",
@ -115,35 +111,29 @@ const char *materialnm[] = { "mysterious", "liquid", "wax", "organic",
"metal", "copper", "silver", "gold", "metal", "copper", "silver", "gold",
"platinum", "mithril", "plastic", "glass", "platinum", "mithril", "plastic", "glass",
"gemstone", "stone" }; "gemstone", "stone" };
//是一个字符串指针数组包含了一些物品材质的名称。这些名称与objclass.h中定义的oc_material值的顺序完全对应。 const char quitchars[] = " \r\n\033";
NEARDATA struct savefile_info sfcap, sfrestinfo, sfsaveinfo;
const char quitchars[] = " \r\n\033";//是一个包含一些表示退出字符的字符串,包括空格、回车、换行和转义字符。 const int shield_static[SHIELD_COUNT] = {
NEARDATA struct savefile_info sfcap, sfrestinfo, sfsaveinfo; //结构体变量,用于保存文件的信息。
const int shield_static[SHIELD_COUNT] = {//是一个整型数组,包含了一些盾牌的静态符号。
S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, /* 7 per row */ S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, /* 7 per row */
S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4,
S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4,
}; };
NEARDATA struct you u;//结构体变量,用于表示玩家角色的状态和属性。 NEARDATA struct you u;
NEARDATA time_t ubirthday; //是一个time_t类型的变量表示玩家角色的出生时间。 NEARDATA time_t ubirthday;
NEARDATA struct u_realtime urealtime; //用于表示游戏时间的实时信息。 NEARDATA struct u_realtime urealtime;
NEARDATA struct obj *uwep, *uarm, *uswapwep, //结构体的指针变量,用于表示玩家角色的装备和物品。 NEARDATA struct obj *uwep, *uarm, *uswapwep,
*uquiver, /* quiver */ *uquiver, /* quiver */
*uarmu, /* under-wear, so to speak */ *uarmu, /* under-wear, so to speak */
*uskin, /* dragon armor, if a dragon */ *uskin, /* dragon armor, if a dragon */
*uarmc, *uarmh, *uarms, *uarmg,*uarmf, *uamul, *uarmc, *uarmh, *uarms, *uarmg,*uarmf, *uamul,
*uright, *uleft, *ublindf, *uchain, *uball; *uright, *uleft, *ublindf, *uchain, *uball;
const char vowels[] = "aeiouAEIOU"; //是一个包含元音字母的字符串,包括小写和大写的元音字母。 const char vowels[] = "aeiouAEIOU";
NEARDATA winid WIN_MESSAGE, WIN_STATUS, WIN_MAP, WIN_INVEN;//是窗口标识符winid类型变量用于表示游戏中的不同窗口。 NEARDATA winid WIN_MESSAGE, WIN_STATUS, WIN_MAP, WIN_INVEN;
const char ynchars[] = "yn"; //是包含一些表示"yes"和"no"的字符的字符串。 const char ynchars[] = "yn";
const char ynqchars[] = "ynq"; const char ynqchars[] = "ynq";
const char ynaqchars[] = "ynaq"; const char ynaqchars[] = "ynaq";
const char ynNaqchars[] = "yn#aq"; const char ynNaqchars[] = "yn#aq";
NEARDATA long yn_number = 0L; NEARDATA long yn_number = 0L;
//这些变量的定义用于实现游戏的逻辑和界面显示等功能。
//其中包括随机数种子、文本输出、文件操作、游戏状态、时间管理、玩家角色属性、装备和物品等。
#ifdef PANICTRACE #ifdef PANICTRACE
const char *ARGV0; const char *ARGV0;

@ -1,3 +1,4 @@
//2023/12/3 大致阅读改代码,并对没有英文注释的代码加上了汉文注释
/* NetHack 3.7 write.c $NHDT-Date: 1596498232 2020/08/03 23:43:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ */ /* NetHack 3.7 write.c $NHDT-Date: 1596498232 2020/08/03 23:43:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@ -62,6 +63,7 @@ cost(struct obj *otmp)
the discoveries list and aren't present in current inventory, the discoveries list and aren't present in current inventory,
so some scrolls with ought to yield True will end up False */ so some scrolls with ought to yield True will end up False */
static boolean static boolean
//判断一个玩家是否知道某个卷轴的名称
label_known(int scrolltype, struct obj *objlist) label_known(int scrolltype, struct obj *objlist)
{ {
struct obj *otmp; struct obj *otmp;
@ -69,24 +71,30 @@ label_known(int scrolltype, struct obj *objlist)
/* only scrolls */ /* only scrolls */
if (objects[scrolltype].oc_class != SCROLL_CLASS) if (objects[scrolltype].oc_class != SCROLL_CLASS)
return FALSE; return FALSE;
/* type known implies full discovery; otherwise, /* type known implies full discovery; otherwise,
user-assigned name implies partial discovery */ user-assigned name implies partial discovery */
if (objects[scrolltype].oc_name_known || objects[scrolltype].oc_uname) if (objects[scrolltype].oc_name_known || objects[scrolltype].oc_uname)
return TRUE; return TRUE;
/* check inventory, including carried containers with known contents */ /* check inventory, including carried containers with known contents */
for (otmp = objlist; otmp; otmp = otmp->nobj) { for (otmp = objlist; otmp; otmp = otmp->nobj) {
if (otmp->otyp == scrolltype && otmp->dknown) if (otmp->otyp == scrolltype && otmp->dknown) // 检查物品种类和标记为已识别的卷轴
return TRUE; return TRUE;
if (Has_contents(otmp) && otmp->cknown
&& label_known(scrolltype, otmp->cobj)) if (Has_contents(otmp) && otmp->cknown // 检查物品是否是容器且已知其内容
&& label_known(scrolltype, otmp->cobj)) // 递归地检查容器内的物品
return TRUE; return TRUE;
} }
/* not found */ /* not found */
return FALSE; return FALSE;
} }
/* getobj callback for object to write on */ /* getobj callback for object to write on */
static int static int
//用于确定物品是否可以写入(即在其上书写符文或咒语)
write_ok(struct obj *obj) write_ok(struct obj *obj)
{ {
if (!obj || (obj->oclass != SCROLL_CLASS && obj->oclass != SPBOOK_CLASS)) if (!obj || (obj->oclass != SCROLL_CLASS && obj->oclass != SPBOOK_CLASS))
@ -237,28 +245,32 @@ dowrite(struct obj *pen)
found: found:
if (i == SCR_BLANK_PAPER || i == SPE_BLANK_PAPER) { if (i == SCR_BLANK_PAPER || i == SPE_BLANK_PAPER) {
You_cant("write that!"); // 如果玩家尝试在空白卷轴或空白法术书上书写
pline("It's obscene!"); You_cant("write that!"); // 提示玩家无法这样做
return ECMD_TIME; pline("It's obscene!"); // 发出警告
} else if (i == SPE_NOVEL) { return ECMD_TIME; // 返回时间消耗
boolean fanfic = !rn2(3), tearup = !rn2(3); } else if (i == SPE_NOVEL) {
// 如果玩家尝试在小说上书写
boolean fanfic = !rn2(3), tearup = !rn2(3);
if (!fanfic) {
You("%s to write the Great Yendorian Novel, but %s inspiration.",
!tearup ? "prepare" : "try",
!Hallucination ? "lack" : "have too much");
} else {
You("%sproduce really %s fan-fiction.",
!tearup ? "start to " : "",
!Hallucination ? "lame" : "awesome");
}
if (!tearup) {
You("give up on the idea.");
} else {
You("tear it up.");
useup(paper); // 销毁使用的纸张
}
return ECMD_TIME; // 返回时间消耗
}
if (!fanfic) {
You("%s to write the Great Yendorian Novel, but %s inspiration.",
!tearup ? "prepare" : "try",
!Hallucination ? "lack" : "have too much");
} else {
You("%sproduce really %s fan-fiction.",
!tearup ? "start to " : "",
!Hallucination ? "lame" : "awesome");
}
if (!tearup) {
You("give up on the idea.");
} else {
You("tear it up.");
useup(paper);
}
return ECMD_TIME;
} else if (i == SPE_BOOK_OF_THE_DEAD) { } else if (i == SPE_BOOK_OF_THE_DEAD) {
pline("No mere dungeon adventurer could write that."); pline("No mere dungeon adventurer could write that.");
return ECMD_TIME; return ECMD_TIME;

@ -0,0 +1,79 @@
用例名:道具使用
执行者:玩家
目标:将玩家装备的道具效果提交到属性面板上
前置条件:
玩家拥有至少一件道具
玩家处于可以与道具交互的状态(例如,非战斗状态)
后置条件:
道具使用后,其效果将被应用
玩家的状态可能因道具效果而改变
主要场景:
玩家选择一个道具。
玩家点击或选择“使用”选项。
游戏判断玩家是否满足使用该道具的条件(例如,是否在战斗中,道具是否为可消耗等)。
如果满足条件,游戏将执行道具效果,并在界面上显示相关信息。
如果道具具有持续效果,游戏将在一段时间内保持这些效果。
如果道具为一次性消耗品,使用后将消失。
玩家可以查看道具使用后的效果和状态变化。
交互动作:
1玩家遇到特殊情况后下达命令cmd.c并apply.c执行来选择使用道具
2装备道具后根据更新后属性面板看能否解决当前问题
3如果能解决则根据宝物使用更新内存分配alloc.c并记录时间date.c参数如果不能解决则继续试用其他宝物
用例交互图
| 玩家
| +---------------+ +--------------+ +-------------+ +-----------+ +-----------+
| | 选择道具 |---------->| 判断条件 |---------->| 显示效果 |---------->| 更新状态 |---------->| 更新UI |---------->| 反馈 |
| +---------------+ +--------------+ +-------------+ +-----------+ +-----------+
| | 游戏系统
| +---------------+ +--------------+ +-------------+ +-----------+ +-----------+
| | 触发条件 |---------->| 验证玩家 |---------->| 获取道具信息|---------->| 执行效果|---------->| 更新UI |---------->| 返回结果 |
| +---------------+ +--------------+ +-------------+ +-----------+ +-----------+
alloc.c
描述:处理游戏中的内存分配。
用例:当游戏需要创建新对象或数据结构时,会使用此模块中的函数来分配所需的内存。
apply.c
描述:处理各种应用的逻辑。
用例:当玩家对其他对象(例如对一个门应用钥匙)或自己应用药物时,相关的逻辑会被处理。
artifact.c
描述处理神器Artifact相关的逻辑。
用例:玩家可能会找到神器,并尝试使用它们或与之互动。此模块处理这些交互的逻辑。
attrib.c
描述:处理属性相关的逻辑。
用例:玩家或敌人可能有各种属性,如攻击力、防御力、速度等。此模块处理这些属性的逻辑。
ball.c
描述处理魔法球Ball相关的逻辑。
用例:魔法球是游戏中的一个对象,玩家可以捡起并使用它。此模块处理与魔法球相关的所有逻辑。
bones.c
描述处理骨头Bones相关的逻辑。
用例:骨头是游戏中一种特殊的对象,当玩家死亡后可能会留下。此模块处理与骨头相关的所有逻辑。
botl.c
描述处理宝物Treasure相关的逻辑。
用例:玩家在游戏中可能会找到各种宝物,如金币、宝石等。此模块处理与这些宝物相关的所有逻辑。
cmd.c
描述:处理命令相关的逻辑。
用例:玩家在游戏中会发出各种命令,如移动、攻击、使用物品等。此模块处理这些命令的逻辑。
date.c
描述:处理日期和时间相关的逻辑。
用例:游戏世界有一个时间流逝的机制,此模块处理与时间流逝、日期等相关的逻辑。
dbridge.c
描述处理桥Bridge相关的逻辑。
用例:桥是游戏中一种特殊的对象或地形,玩家可能需要跨过或与之互动。此模块处理与桥相关的所有逻辑。
各个函数的分类属性以及相关的简单逻辑关系如下:
玩家-》通过命令cmd.c再由apply.c来执行
系统运行-》
内存分配alloc.c
时间date.c
显示面板-》
属性面板attrib.c
道具-》
桥dbridge.c
宝物botl.c
骨头bones.c
魔法球ball.c
神器artifact.c
Loading…
Cancel
Save