OSDN Git Service

update year to 2022
[jnethack/source.git] / src / region.c
index 8589100..332040e 100644 (file)
@@ -1,7 +1,12 @@
-/* NetHack 3.6 region.c        $NHDT-Date: 1446892454 2015/11/07 10:34:14 $  $NHDT-Branch: master $:$NHDT-Revision: 1.36 $ */
+/* NetHack 3.6 region.c        $NHDT-Date: 1573957877 2019/11/17 02:31:17 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.45 $ */
 /* Copyright (c) 1996 by Jean-Christophe Collet  */
 /* NetHack may be freely redistributed.  See license for details. */
 
+/* JNetHack Copyright */
+/* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2022            */
+/* JNetHack may be freely redistributed.  See license for details. */
+
 #include "hack.h"
 #include "lev.h"
 
@@ -91,18 +96,18 @@ int nrect;
     NhRegion *reg;
 
     reg = (NhRegion *) alloc(sizeof(NhRegion));
+    (void) memset((genericptr_t)reg, 0, sizeof(NhRegion));
     /* Determines bounding box */
     if (nrect > 0) {
         reg->bounding_box = rects[0];
     } else {
-        reg->bounding_box.lx = 99;
-        reg->bounding_box.ly = 99;
-        reg->bounding_box.hx = 0;
+        reg->bounding_box.lx = COLNO;
+        reg->bounding_box.ly = ROWNO;
+        reg->bounding_box.hx = 0; /* 1 */
         reg->bounding_box.hy = 0;
     }
     reg->nrects = nrect;
-    reg->rects =
-        nrect > 0 ? (NhRect *) alloc((sizeof(NhRect)) * nrect) : (NhRect *) 0;
+    reg->rects = (nrect > 0) ? (NhRect *) alloc(nrect * sizeof (NhRect)) : 0;
     for (i = 0; i < nrect; i++) {
         if (rects[i].lx < reg->bounding_box.lx)
             reg->bounding_box.lx = rects[i].lx;
@@ -145,10 +150,10 @@ NhRect *rect;
 {
     NhRect *tmp_rect;
 
-    tmp_rect = (NhRect *) alloc(sizeof(NhRect) * (reg->nrects + 1));
+    tmp_rect = (NhRect *) alloc((reg->nrects + 1) * sizeof (NhRect));
     if (reg->nrects > 0) {
         (void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects,
-                      (sizeof(NhRect) * reg->nrects));
+                      reg->nrects * sizeof (NhRect));
         free((genericptr_t) reg->rects);
     }
     tmp_rect[reg->nrects] = *rect;
@@ -177,7 +182,7 @@ struct monst *mon;
     unsigned *tmp_m;
 
     if (reg->max_monst <= reg->n_monst) {
-        tmp_m = (unsigned *) alloc(sizeof(unsigned)
+        tmp_m = (unsigned *) alloc(sizeof (unsigned)
                                    * (reg->max_monst + MONST_INC));
         if (reg->max_monst > 0) {
             for (i = 0; i < reg->max_monst; i++)
@@ -297,10 +302,10 @@ NhRegion *reg;
     if (max_regions <= n_regions) {
         tmp_reg = regions;
         regions =
-            (NhRegion **) alloc(sizeof(NhRegion *) * (max_regions + 10));
+            (NhRegion **) alloc((max_regions + 10) * sizeof (NhRegion *));
         if (max_regions > 0) {
             (void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg,
-                          max_regions * sizeof(NhRegion *));
+                          max_regions * sizeof (NhRegion *));
             free((genericptr_t) tmp_reg);
         }
         max_regions += 10;
@@ -340,6 +345,11 @@ NhRegion *reg;
     if (i == n_regions)
         return;
 
+    /* remove region before potential newsym() calls, but don't free it yet */
+    if (--n_regions != i)
+        regions[i] = regions[n_regions];
+    regions[n_regions] = (NhRegion *) 0;
+
     /* Update screen if necessary */
     reg->ttl = -2L; /* for visible_region_at */
     if (reg->visible)
@@ -349,9 +359,6 @@ NhRegion *reg;
                     newsym(x, y);
 
     free_region(reg);
-    regions[i] = regions[n_regions - 1];
-    regions[n_regions - 1] = (NhRegion *) 0;
-    n_regions--;
 }
 
 /*
@@ -408,7 +415,7 @@ run_regions()
                 struct monst *mtmp =
                     find_mid(regions[i]->monsters[j], FM_FMON);
 
-                if (!mtmp || mtmp->mhp <= 0
+                if (!mtmp || DEADMONSTER(mtmp)
                     || (*callbacks[f_indx])(regions[i], mtmp)) {
                     /* The monster died, remove it from list */
                     k = (regions[i]->n_monst -= 1);
@@ -428,26 +435,27 @@ boolean
 in_out_region(x, y)
 xchar x, y;
 {
-    int i, f_indx;
+    int i, f_indx = 0;
 
-    /* First check if we can do the move */
+    /* First check if hero can do the move */
     for (i = 0; i < n_regions; i++) {
-        if (inside_region(regions[i], x, y) && !hero_inside(regions[i])
-            && !regions[i]->attach_2_u) {
-            if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
-                if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
-                    return FALSE;
-        } else if (hero_inside(regions[i]) && !inside_region(regions[i], x, y)
-                   && !regions[i]->attach_2_u) {
-            if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
-                if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
-                    return FALSE;
+        if (regions[i]->attach_2_u)
+            continue;
+        if (inside_region(regions[i], x, y)
+            ? (!hero_inside(regions[i])
+               && (f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
+            : (hero_inside(regions[i])
+               && (f_indx = regions[i]->can_leave_f) != NO_CALLBACK)) {
+            if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
+                return FALSE;
         }
     }
 
-    /* Callbacks for the regions we do leave */
-    for (i = 0; i < n_regions; i++)
-        if (hero_inside(regions[i]) && !regions[i]->attach_2_u
+    /* Callbacks for the regions hero does leave */
+    for (i = 0; i < n_regions; i++) {
+        if (regions[i]->attach_2_u)
+            continue;
+        if (hero_inside(regions[i])
             && !inside_region(regions[i], x, y)) {
             clear_hero_inside(regions[i]);
             if (regions[i]->leave_msg != (const char *) 0)
@@ -455,10 +463,13 @@ xchar x, y;
             if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
                 (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
         }
+    }
 
-    /* Callbacks for the regions we do enter */
-    for (i = 0; i < n_regions; i++)
-        if (!hero_inside(regions[i]) && !regions[i]->attach_2_u
+    /* Callbacks for the regions hero does enter */
+    for (i = 0; i < n_regions; i++) {
+        if (regions[i]->attach_2_u)
+            continue;
+        if (!hero_inside(regions[i])
             && inside_region(regions[i], x, y)) {
             set_hero_inside(regions[i]);
             if (regions[i]->enter_msg != (const char *) 0)
@@ -466,53 +477,59 @@ xchar x, y;
             if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
                 (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
         }
+    }
+
     return TRUE;
 }
 
 /*
- * check whether a monster enters/leaves one or more region.
-*/
+ * check whether a monster enters/leaves one or more regions.
+ */
 boolean
 m_in_out_region(mon, x, y)
 struct monst *mon;
 xchar x, y;
 {
-    int i, f_indx;
+    int i, f_indx = 0;
 
-    /* First check if we can do the move */
+    /* First check if mon can do the move */
     for (i = 0; i < n_regions; i++) {
-        if (inside_region(regions[i], x, y) && !mon_in_region(regions[i], mon)
-            && regions[i]->attach_2_m != mon->m_id) {
-            if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
-                if (!(*callbacks[f_indx])(regions[i], mon))
-                    return FALSE;
-        } else if (mon_in_region(regions[i], mon)
-                   && !inside_region(regions[i], x, y)
-                   && regions[i]->attach_2_m != mon->m_id) {
-            if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
-                if (!(*callbacks[f_indx])(regions[i], mon))
-                    return FALSE;
+        if (regions[i]->attach_2_m == mon->m_id)
+            continue;
+        if (inside_region(regions[i], x, y)
+            ? (!mon_in_region(regions[i], mon)
+               && (f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
+            : (mon_in_region(regions[i], mon)
+               && (f_indx = regions[i]->can_leave_f) != NO_CALLBACK)) {
+            if (!(*callbacks[f_indx])(regions[i], mon))
+                return FALSE;
         }
     }
 
-    /* Callbacks for the regions we do leave */
-    for (i = 0; i < n_regions; i++)
+    /* Callbacks for the regions mon does leave */
+    for (i = 0; i < n_regions; i++) {
+        if (regions[i]->attach_2_m == mon->m_id)
+            continue;
         if (mon_in_region(regions[i], mon)
-            && regions[i]->attach_2_m != mon->m_id
             && !inside_region(regions[i], x, y)) {
             remove_mon_from_reg(regions[i], mon);
             if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
                 (void) (*callbacks[f_indx])(regions[i], mon);
         }
+    }
 
-    /* Callbacks for the regions we do enter */
-    for (i = 0; i < n_regions; i++)
-        if (!hero_inside(regions[i]) && !regions[i]->attach_2_u
+    /* Callbacks for the regions mon does enter */
+    for (i = 0; i < n_regions; i++) {
+        if (regions[i]->attach_2_m == mon->m_id)
+            continue;
+        if (!mon_in_region(regions[i], mon)
             && inside_region(regions[i], x, y)) {
             add_mon_to_reg(regions[i], mon);
             if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
                 (void) (*callbacks[f_indx])(regions[i], mon);
         }
+    }
+
     return TRUE;
 }
 
@@ -598,10 +615,12 @@ xchar x, y;
 {
     register int i;
 
-    for (i = 0; i < n_regions; i++)
-        if (inside_region(regions[i], x, y) && regions[i]->visible
-            && regions[i]->ttl != -2L)
+    for (i = 0; i < n_regions; i++) {
+        if (!regions[i]->visible || regions[i]->ttl == -2L)
+            continue;
+        if (inside_region(regions[i], x, y))
             return regions[i];
+    }
     return (NhRegion *) 0;
 }
 
@@ -763,6 +782,32 @@ boolean ghostly; /* If a bones file restore */
             reset_region_mids(regions[i]);
 }
 
+/* to support '#stats' wizard-mode command */
+void
+region_stats(hdrfmt, hdrbuf, count, size)
+const char *hdrfmt;
+char *hdrbuf;
+long *count, *size;
+{
+    NhRegion *rg;
+    int i;
+
+    /* other stats formats take one parameter; this takes two */
+    Sprintf(hdrbuf, hdrfmt, (long) sizeof (NhRegion), (long) sizeof (NhRect));
+    *count = (long) n_regions; /* might be 0 even though max_regions isn't */
+    *size = (long) max_regions * (long) sizeof (NhRegion);
+    for (i = 0; i < n_regions; ++i) {
+        rg = regions[i];
+        *size += (long) rg->nrects * (long) sizeof (NhRect);
+        if (rg->enter_msg)
+            *size += (long) (strlen(rg->enter_msg) + 1);
+        if (rg->leave_msg)
+            *size += (long) (strlen(rg->leave_msg) + 1);
+        *size += (long) rg->max_monst * (long) sizeof *rg->monsters;
+    }
+    /* ? */
+}
+
 /* update monster IDs for region being loaded from bones; `ghostly' implied */
 STATIC_OVL void
 reset_region_mids(reg)
@@ -831,15 +876,27 @@ genericptr_t p2;
 
     if (p2 == (genericptr_t) 0) { /* That means the player */
         if (!Blind)
-            You("bump into %s. Ouch!",
+#if 0 /*JP*/
+            You("bump into %s.  Ouch!",
                 Hallucination ? "an invisible tree"
                               : "some kind of invisible wall");
+#else
+            You("%s\82É\82Ô\82¿\82 \82½\82Á\82½\81D\82¢\82Ä\82Á\81I",
+                Hallucination ? "\96Ú\82É\8c©\82¦\82È\82¢\96Ø"
+                              : "\82È\82ñ\82ç\82©\82Ì\96Ú\82É\8c©\82¦\82È\82¢\95Ç");
+#endif
         else
+/*JP
             pline("Ouch!");
+*/
+            pline("\82¢\82Ä\82Á\81I");
     } else {
         mtmp = (struct monst *) p2;
         if (canseemon(mtmp))
+/*JP
             pline("%s bumps into %s!", Monnam(mtmp), something);
+*/
+            pline("%s\82Í%s\82É\82Ô\82¿\82 \82½\82Á\82½\81I", Monnam(mtmp), something);
     }
     return FALSE;
 }
@@ -921,17 +978,26 @@ genericptr_t p2;
     struct monst *mtmp;
     int dam;
 
+    /*
+     * Gas clouds can't be targetted at water locations, but they can
+     * start next to water and spread over it.
+     */
+
     reg = (NhRegion *) p1;
     dam = reg->arg.a_int;
     if (p2 == (genericptr_t) 0) { /* This means *YOU* Bozo! */
-        if (u.uinvulnerable || nonliving(youmonst.data) || Breathless)
+        if (u.uinvulnerable || nonliving(youmonst.data) || Breathless
+            || Underwater)
             return FALSE;
         if (!Blind) {
+/*JP
             Your("%s sting.", makeplural(body_part(EYE)));
+*/
+            Your("%s\82ª\83`\83N\83`\83N\82µ\82½\81D", body_part(EYE));
             make_blinded(1L, FALSE);
         }
         if (!Poison_resistance) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("%s is burning your %s!", Something,
                   makeplural(body_part(LUNG)));
 #else
@@ -956,16 +1022,27 @@ genericptr_t p2;
     } else { /* A monster is inside the cloud */
         mtmp = (struct monst *) p2;
 
-        /* Non living and non breathing monsters are not concerned */
+        /* Non living and non breathing monsters are not concerned;
+           adult green dragon is not affected by gas cloud, baby one is */
         if (!(nonliving(mtmp->data) || is_vampshifter(mtmp))
-            && !breathless(mtmp->data)) {
+            && !breathless(mtmp->data)
+            /* not is_swimmer(); assume that non-fish are swimming on
+               the surface and breathing the air above it periodically
+               unless located at water spot on plane of water */
+            && !((mtmp->data->mlet == S_EEL || Is_waterlevel(&u.uz))
+                 && is_pool(mtmp->mx, mtmp->my))
+            /* exclude monsters with poison gas breath attack:
+               adult green dragon and Chromatic Dragon (and iron golem,
+               but nonliving() and breathless() tests also catch that) */
+            && !(attacktype_fordmg(mtmp->data, AT_BREA, AD_DRST)
+                 || attacktype_fordmg(mtmp->data, AT_BREA, AD_RBRE))) {
             if (cansee(mtmp->mx, mtmp->my))
 /*JP
                 pline("%s coughs!", Monnam(mtmp));
 */
                 pline("%s\82Í\8aP\82«\82±\82ñ\82¾\81I", Monnam(mtmp));
             if (heros_fault(reg))
-                setmangry(mtmp);
+                setmangry(mtmp, TRUE);
             if (haseyes(mtmp->data) && mtmp->mcansee) {
                 mtmp->mblinded = 1;
                 mtmp->mcansee = 0;
@@ -973,7 +1050,7 @@ genericptr_t p2;
             if (resists_poison(mtmp))
                 return FALSE;
             mtmp->mhp -= rnd(dam) + 5;
-            if (mtmp->mhp <= 0) {
+            if (DEADMONSTER(mtmp)) {
                 if (heros_fault(reg))
                     killed(mtmp);
                 else
@@ -981,7 +1058,7 @@ genericptr_t p2;
                     monkilled(mtmp, "gas cloud", AD_DRST);
 */
                     monkilled(mtmp, "\83K\83X\89_", AD_DRST);
-                if (mtmp->mhp <= 0) { /* not lifesaved */
+                if (DEADMONSTER(mtmp)) { /* not lifesaved */
                     return TRUE;
                 }
             }
@@ -1077,10 +1154,16 @@ region_safety()
         safe_teleds(FALSE);
     } else if (r) {
         remove_region(r);
+/*JP
         pline_The("gas cloud enveloping you dissipates.");
+*/
+        pline("\82 \82È\82½\82ð\95ï\82ñ\82Å\82¢\82½\83K\83X\89_\82Í\8fÁ\82¦\82½\81D");
     } else {
         /* cloud dissipated on its own, so nothing needs to be done */
+/*JP
         pline_The("gas cloud has dissipated.");
+*/
+        pline("\83K\83X\89_\82Í\8fÁ\82¦\82½\81D");
     }
     /* maybe cure blindness too */
     if ((Blinded & TIMEOUT) == 1L)