]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/retreat.c
retreat: Reject invalid retreat paths
[empserver] / src / lib / subs / retreat.c
index d3a0b42e3712d64c889749297b7b241fafd1315e..d850aa0c1b7eede4fc7e9ec87d1c180f6c031075 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2005, Dave Pare, Jeff Bailey, Thomas Ruschak,
- *                           Ken Stevens, Steve McClure
+ *  Copyright (C) 1986-2014, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *                Ken Stevens, Steve McClure, Markus Armbruster
  *
- *  This program is free software; you can redistribute it and/or modify
+ *  Empire is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
+ *  the Free Software Foundation, either version 3 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  *  ---
  *
- *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
- *  related information and legal notices. It is expected that any future
- *  projects/authors will amend these files as needed.
+ *  See files README, COPYING and CREDITS in the root of the source
+ *  tree for related information and legal notices.  It is expected
+ *  that future projects/authors will amend these files as needed.
  *
  *  ---
  *
  *  retreat.c: Retreat subroutines
- * 
+ *
  *  Known contributors to this file:
  *     Steve McClure, 2000
- *     
+ *     Ron Koenderink, 2005-2006
+ *     Markus Armbruster, 2006-2014
  */
 
-#include <string.h>
+#include <config.h>
+
+#include "chance.h"
+#include "damage.h"
+#include "file.h"
+#include "land.h"
+#include "map.h"
 #include "misc.h"
-#include "player.h"
 #include "nat.h"
-#include "retreat.h"
-#include "ship.h"
-#include "land.h"
-#include "sect.h"
 #include "news.h"
-#include "xy.h"
 #include "nsc.h"
+#include "optlist.h"
 #include "path.h"
-#include "file.h"
-#include "damage.h"
+#include "player.h"
 #include "prototypes.h"
-#include "optlist.h"
+#include "retreat.h"
+#include "sect.h"
+#include "ship.h"
+#include "xy.h"
 
-static int findcondition(s_char);
-static int retreat_land1(struct lndstr *, s_char, int);
-static int retreat_ship1(struct shpstr *, s_char, int);
+static int findcondition(char);
+static int retreat_land1(struct lndstr *, char, int);
+static int retreat_ship1(struct shpstr *, char, int);
 
 struct ccode {
-    s_char code;
-    s_char *desc[2];
-} conditions[] = {
-    {
-       'i', {
-    "retreated with a damaged friend", "was damaged",},}, {
-       't', {
-    "retreated with a torpedoed ship", "was hit by a torpedo",},}, {
-       's', {
-    "retreated with a ship scared by sonar",
-               "detected a sonar ping",},}, {
-       'h', {
-    "retreated with a helpless ship",
-               "was fired upon with no one able to defend it",},}, {
-       'b', {
-    "retreated with a bombed friend", "was bombed",},}, {
-       'd', {
-    "retreated with a depth-charged ship", "was depth-charged",},}, {
-       'u', {
-    "retreated with a boarded ship", "was boarded",},}, {
-       0, {
-"", ""}},};
+    char code;
+    char *desc[2];
+};
+
+static struct ccode conditions[] = {
+    { 'i', { "retreated with a damaged friend",
+            "was damaged" } },
+    { 't', { "retreated with a torpedoed ship",
+            "was hit by a torpedo" } },
+    { 's', { "retreated with a ship scared by sonar",
+            "detected a sonar ping" } },
+    { 'h', { "retreated with a helpless ship",
+            "was fired upon with no one able to defend it" } },
+    { 'b', { "retreated with a bombed friend",
+            "was bombed" } },
+    { 'd', { "retreated with a depth-charged ship",
+            "was depth-charged" } },
+    { 'u', { "retreated with a boarded ship", "was boarded" } },
+    { 0,   { "panicked", "panicked"} }
+};
 
 int
 check_retreat_and_do_shipdamage(struct shpstr *sp, int dam)
@@ -91,24 +92,25 @@ check_retreat_and_do_shipdamage(struct shpstr *sp, int dam)
 }
 
 void
-retreat_ship(struct shpstr *sp, s_char code)
+retreat_ship(struct shpstr *sp, char code)
 {
     struct nstr_item ni;
     struct shpstr ship;
-    s_char buf[2];
+
+    if (sp->shp_effic < SHIP_MINEFF || CANT_HAPPEN(!sp->shp_own))
+       return;
+    if (sp->shp_own == player->cnum)
+       return;
+
+    retreat_ship1(sp, code, 1);
+    if (sp->shp_rpath[0] == 0)
+       sp->shp_rflags = 0;
 
     if (sp->shp_rflags & RET_GROUP) {
-       buf[0] = sp->shp_fleet;
-       buf[1] = 0;
-       snxtitem(&ni, EF_SHIP, buf);
-       while (nxtitem(&ni, (s_char *)&ship))
-           if ((ship.shp_fleet == buf[0]) &&
-               (ship.shp_own == sp->shp_own)) {
-               if (ship.shp_uid == sp->shp_uid) {
-                   retreat_ship1(sp, code, 1);
-                   if (sp->shp_rpath[0] == 0)
-                       sp->shp_rflags = 0;
-               } else {
+       snxtitem_group(&ni, EF_SHIP, sp->shp_fleet);
+       while (nxtitem(&ni, &ship))
+           if (ship.shp_own == sp->shp_own) {
+               if (ship.shp_uid != sp->shp_uid) {
                    retreat_ship1(&ship, code, 0);
                    getship(ship.shp_uid, &ship);
                    if (ship.shp_rpath[0] == 0) {
@@ -117,21 +119,17 @@ retreat_ship(struct shpstr *sp, s_char code)
                    }
                }
            }
-    } else {
-       retreat_ship1(sp, code, 1);
-       if (sp->shp_rpath[0] == 0)
-           sp->shp_rflags = 0;
     }
 }
 
 static int
-retreat_ship1(struct shpstr *sp, s_char code, int orig)
+retreat_ship1(struct shpstr *sp, char code, int orig)
 
 
                        /* Is this the originally scared ship, or a follower */
 {
     struct sctstr sect;
-    int n;
+    int i;
     int m;
     int max;
     int dir;
@@ -139,29 +137,11 @@ retreat_ship1(struct shpstr *sp, s_char code, int orig)
     coord newy;
     coord dx;
     coord dy;
-    int stopping;
     int mines;
     int shells;
     double mobcost;
     struct mchrstr *mcp;
-    int time_to_stop;
-
-    sp->shp_mission = 0;
-    if (sp->shp_own == 0)
-       return 0;
-
-    if (isupper(code))
-       code = tolower(code);
-
-    n = 0;
-    if (sp->shp_effic < SHIP_MINEFF) {
-       wu(0, sp->shp_own,
-          "%s %s,\nbut it died in the attack, and so couldn't retreat!\n",
-          prship(sp), conditions[findcondition(code)].desc[orig]);
-       if (!orig)
-           putship(sp->shp_uid, sp);
-       return 0;
-    }
+    int changed;
 
     if (opt_SAIL) {
        /* can't retreat a ship that's sailin, bad things happend */
@@ -169,8 +149,6 @@ retreat_ship1(struct shpstr *sp, s_char code, int orig)
            wu(0, sp->shp_own,
               "%s %s,\nbut had sailing orders, and couldn't retreat!\n",
               prship(sp), conditions[findcondition(code)].desc[orig]);
-           if (!orig)
-               putship(sp->shp_uid, sp);
            return 0;
        }
     }
@@ -179,59 +157,41 @@ retreat_ship1(struct shpstr *sp, s_char code, int orig)
        wu(0, sp->shp_own,
           "%s %s,\nbut had no crew, and couldn't retreat!\n", prship(sp),
           conditions[findcondition(code)].desc[orig]);
-       if (!orig)
-           putship(sp->shp_uid, sp);
        return 0;
     }
 
     getsect(sp->shp_x, sp->shp_y, &sect);
-    switch (check_nav(&sect)) {
-    case CN_CONSTRUCTION:
+    switch (shp_check_nav(sp, &sect)) {
+    case NAV_02:
+    case NAV_60:
        wu(0, sp->shp_own,
           "%s %s,\nbut was caught in a construction zone, and couldn't retreat!\n",
           prship(sp), conditions[findcondition(code)].desc[orig]);
-       if (!orig)
-           putship(sp->shp_uid, sp);
        return 0;
-    case CN_LANDLOCKED:
+    case NAV_NONE:
+    case NAV_CANAL:
        wu(0, sp->shp_own,
           "%s %s,\nbut was landlocked, and couldn't retreat!\n",
           prship(sp), conditions[findcondition(code)].desc[orig]);
-       if (!orig)
-           putship(sp->shp_uid, sp);
        return 0;
-       /*NOTREACHED*/
-    case CN_NAVIGABLE:
+    case NAVOK:
        break;
-    case CN_ERROR:
     default:
+       CANT_REACH();
        wu(0, sp->shp_own,
           "%s %s,\nbut was subject to an empire error, and couldn't retreat!\n",
           prship(sp), conditions[findcondition(code)].desc[orig]);
-       if (!orig)
-           putship(sp->shp_uid, sp);
        return 0;
-       /*NOTREACHED*/
     }
 
     if (sp->shp_mobil <= 0.0) {
        wu(0, sp->shp_own,
           "%s %s,\nbut had no mobility, and couldn't retreat!\n",
           prship(sp), conditions[findcondition(code)].desc[orig]);
-       if (!orig)
-           putship(sp->shp_uid, sp);
        return 0;
     }
 
-    n = (-1 * MAX_RETREAT);
-    stopping = 0;
-    time_to_stop = 0;
-    while ((!stopping) && n) {
-       dx = dy = 0;
-       if (sp->shp_rpath[0] == 0 || sp->shp_rpath[0] == 0) {
-           stopping = 1;
-           continue;
-       }
+    for (i = 0; i < MAX_RETREAT && sp->shp_rpath[0]; i++) {
        if (sp->shp_mobil <= 0.0) {
            wu(0, sp->shp_own,
               "%s %s,\nbut ran out of mobility, and couldn't retreat fully!\n",
@@ -240,28 +200,22 @@ retreat_ship1(struct shpstr *sp, s_char code, int orig)
                putship(sp->shp_uid, sp);
            return 0;
        }
-       dir = chkdir(sp->shp_rpath[0], DIR_STOP, DIR_VIEW);
+       dir = chkdir(sp->shp_rpath[0], DIR_STOP, DIR_LAST);
        memmove(sp->shp_rpath, sp->shp_rpath+1, sizeof(sp->shp_rpath) - 1);
-       if (dir == -1)
-           continue;
-       if (dir == DIR_STOP)
-           stopping++;
-       else {
-           dx = diroff[dir][0];
-           dy = diroff[dir][1];
-       }
-       n++;
+       if (dir == DIR_STOP || CANT_HAPPEN(dir < 0))
+           break;
+       dx = diroff[dir][0];
+       dy = diroff[dir][1];
 
        mcp = &mchr[(int)sp->shp_type];
        newx = xnorm(sp->shp_x + dx);
        newy = ynorm(sp->shp_y + dy);
-       mobcost = sp->shp_effic * 0.01 * sp->shp_speed;
-       mobcost = 480.0 / (mobcost + techfact(sp->shp_tech, mobcost));
+       mobcost = shp_mobcost(sp);
 
        getsect(newx, newy, &sect);
-       if (check_nav(&sect) != CN_NAVIGABLE ||
-           (sect.sct_own && !player->owner &&
-            getrel(getnatp(sect.sct_own), sp->shp_own) < FRIENDLY)) {
+       if (shp_check_nav(sp, &sect) != NAVOK ||
+           (sect.sct_own
+            && relations_with(sect.sct_own, sp->shp_own) < FRIENDLY)) {
            wu(0, sp->shp_own, "%s %s,\nbut could not retreat to %s!\n",
               prship(sp), conditions[findcondition(code)].desc[orig],
               xyas(newx, newy, sp->shp_own));
@@ -272,24 +226,37 @@ retreat_ship1(struct shpstr *sp, s_char code, int orig)
        sp->shp_x = newx;
        sp->shp_y = newy;
        sp->shp_mobil -= mobcost;
-       if (stopping)
-           continue;
+       sp->shp_mission = 0;
 
        mines = sect.sct_mines;
-       if ((mcp->m_flags & M_SWEEP) && mines > 0 && !player->owner) {
+       changed = 0;
+       if (sect.sct_type != SCT_WATER || mines <= 0)
+           continue;
+       if (mcp->m_flags & M_SWEEP) {
            max = mcp->m_item[I_SHELL];
            shells = sp->shp_item[I_SHELL];
            for (m = 0; mines > 0 && m < 5; m++) {
                if (chance(0.66)) {
                    mines--;
-                   shells = min(max, shells + 1);
+                   shells = MIN(max, shells + 1);
+                   changed |= map_set(sp->shp_own, sp->shp_x, sp->shp_y,
+                                      'X', 0);
                }
            }
-           sect.sct_mines = mines;
-           sect.sct_item[I_SHELL] = shells;
-           putsect(&sect);
+           if (sect.sct_mines != mines) {
+               wu(0, sp->shp_own,
+                  "%s cleared %d mine%s in %s while retreating\n",
+                  prship(sp), sect.sct_mines - mines,
+                  splur(sect.sct_mines - mines),
+                  xyas(newx, newy, sp->shp_own));
+               sect.sct_mines = mines;
+               sp->shp_item[I_SHELL] = shells;
+               putsect(&sect);
+           }
+           if (changed)
+               writemap(sp->shp_own);
        }
-       if (mines > 0 && !player->owner && chance(DMINE_HITCHANCE(mines))) {
+       if (chance(DMINE_HITCHANCE(mines))) {
            wu(0, sp->shp_own,
               "%s %s,\nand hit a mine in %s while retreating!\n",
               prship(sp), conditions[findcondition(code)].desc[orig],
@@ -298,21 +265,19 @@ retreat_ship1(struct shpstr *sp, s_char code, int orig)
            m = MINE_DAMAGE();
            shipdamage(sp, m);
            mines--;
+           if (map_set(sp->shp_own, sp->shp_x, sp->shp_y, 'X', 0))
+               writemap(sp->shp_own);
            sect.sct_mines = mines;
            putsect(&sect);
-           if (sp->shp_effic < SHIP_MINEFF)
-               time_to_stop = 1;
            if (!orig)
                putship(sp->shp_uid, sp);
            return 0;
        }
-       if (time_to_stop)
-           stopping = 1;
     }
 
     if (orig) {
-       wu(0, sp->shp_own, "%s %s, and retreated to %s\n", prship(sp),
-          conditions[findcondition(code)].desc[orig],
+       wu(0, sp->shp_own, "%s %s, and retreated to %s\n",
+          prship(sp), conditions[findcondition(code)].desc[orig],
           xyas(sp->shp_x, sp->shp_y, sp->shp_own));
     } else {
        wu(0, sp->shp_own, "%s %s, and ended up at %s\n",
@@ -325,43 +290,14 @@ retreat_ship1(struct shpstr *sp, s_char code, int orig)
     return 1;
 }
 
-#if 0
 static int
-check_nav(sect)
-struct sctstr *sect;
+findcondition(char code)
 {
-    switch (dchr[sect->sct_type].d_flg & 03) {
-    case NAVOK:
-       break;
+    int i;
 
-    case NAV_02:
-       if (sect->sct_effic < 2)
-           return CN_CONSTRUCTION;
-       break;
-    case NAV_60:
-       if (sect->sct_effic < 60)
-           return CN_CONSTRUCTION;
-       break;
-    default:
-       return CN_LANDLOCKED;
-    }
-    return CN_NAVIGABLE;
-}
-#endif
-
-static int
-findcondition(s_char code)
-{
-    int x;
-
-    x = 0;
-    while (conditions[x].code) {
-       if (conditions[x].code == code)
-           return (x);
-       x++;
-    }
-
-    return (x);
+    for (i = 0; conditions[i].code && conditions[i].code != code; i++) ;
+    CANT_HAPPEN(!conditions[i].code);
+    return i;
 }
 
 int
@@ -378,23 +314,25 @@ check_retreat_and_do_landdamage(struct lndstr *lp, int dam)
 }
 
 void
-retreat_land(struct lndstr *lp, s_char code)
+retreat_land(struct lndstr *lp, char code)
 {
     struct nstr_item ni;
     struct lndstr land;
-    s_char buf[2];
+
+    if (lp->lnd_effic < LAND_MINEFF || CANT_HAPPEN(!lp->lnd_own))
+       return;
+    if (lp->lnd_own == player->cnum)
+       return;
+
+    retreat_land1(lp, code, 1);
+    if (lp->lnd_rpath[0] == 0)
+       lp->lnd_rflags = 0;
 
     if (lp->lnd_rflags & RET_GROUP) {
-       buf[0] = lp->lnd_army;
-       buf[1] = 0;
-       snxtitem(&ni, EF_SHIP, buf);
-       while (nxtitem(&ni, (s_char *)&land))
-           if ((land.lnd_army == buf[0]) && (land.lnd_own == lp->lnd_own)) {
-               if (land.lnd_uid == lp->lnd_uid) {
-                   retreat_land1(lp, code, 1);
-                   if (lp->lnd_rpath[0] == 0)
-                       lp->lnd_rflags = 0;
-               } else {
+       snxtitem_group(&ni, EF_LAND, lp->lnd_army);
+       while (nxtitem(&ni, &land))
+           if (land.lnd_own == lp->lnd_own) {
+               if (land.lnd_uid != lp->lnd_uid) {
                    retreat_land1(&land, code, 0);
                    getland(land.lnd_uid, &land);
                    if (land.lnd_rpath[0] == 0) {
@@ -403,21 +341,17 @@ retreat_land(struct lndstr *lp, s_char code)
                    }
                }
            }
-    } else {
-       retreat_land1(lp, code, 1);
-       if (lp->lnd_rpath[0] == 0)
-           lp->lnd_rflags = 0;
     }
 }
 
 static int
-retreat_land1(struct lndstr *lp, s_char code, int orig)
+retreat_land1(struct lndstr *lp, char code, int orig)
 
 
                        /* Is this the originally scared unit, or a follower */
 {
     struct sctstr sect;
-    int n;
+    int i;
     int m;
     int max;
     int dir;
@@ -425,29 +359,10 @@ retreat_land1(struct lndstr *lp, s_char code, int orig)
     coord newy;
     coord dx;
     coord dy;
-    int stopping;
     int mines;
     int shells;
     double mobcost;
     struct lchrstr *lcp;
-    int time_to_stop;
-
-    lp->lnd_mission = 0;
-    if (lp->lnd_own == 0)
-       return 0;
-
-    if (isupper(code))
-       code = tolower(code);
-
-    n = 0;
-    if (lp->lnd_effic < LAND_MINEFF) {
-       wu(0, lp->lnd_own,
-          "%s %s,\nbut it died in the attack, and so couldn't retreat!\n",
-          prland(lp), conditions[findcondition(code)].desc[orig]);
-       if (!orig)
-           putland(lp->lnd_uid, lp);
-       return 0;
-    }
 
     getsect(lp->lnd_x, lp->lnd_y, &sect);
 
@@ -455,20 +370,10 @@ retreat_land1(struct lndstr *lp, s_char code, int orig)
        wu(0, lp->lnd_own,
           "%s %s,\nbut had no mobility, and couldn't retreat!\n",
           prland(lp), conditions[findcondition(code)].desc[orig]);
-       if (!orig)
-           putland(lp->lnd_uid, lp);
        return 0;
     }
 
-    n = (-1 * MAX_RETREAT);
-    stopping = 0;
-    time_to_stop = 0;
-    while ((!stopping) && n) {
-       dx = dy = 0;
-       if (lp->lnd_rpath[0] == 0 || lp->lnd_rpath[0] == 0) {
-           stopping = 1;
-           continue;
-       }
+    for (i = 0; i < MAX_RETREAT && lp->lnd_rpath[0]; i++) {
        if (lp->lnd_mobil <= 0.0) {
            wu(0, lp->lnd_own,
               "%s %s,\nbut ran out of mobility, and couldn't retreat fully!\n",
@@ -477,28 +382,22 @@ retreat_land1(struct lndstr *lp, s_char code, int orig)
                putland(lp->lnd_uid, lp);
            return 0;
        }
-       dir = chkdir(lp->lnd_rpath[0], DIR_STOP, DIR_VIEW);
+       dir = chkdir(lp->lnd_rpath[0], DIR_STOP, DIR_LAST);
        memmove(lp->lnd_rpath, lp->lnd_rpath+1, sizeof(lp->lnd_rpath) - 1);
-       if (dir == -1)
-           continue;
-       if (dir == DIR_STOP)
-           stopping++;
-       else {
-           dx = diroff[dir][0];
-           dy = diroff[dir][1];
-       }
-       n++;
+       if (dir == DIR_STOP || CANT_HAPPEN(dir < 0))
+           break;
+       dx = diroff[dir][0];
+       dy = diroff[dir][1];
 
        lcp = &lchr[(int)lp->lnd_type];
        newx = xnorm(lp->lnd_x + dx);
        newy = ynorm(lp->lnd_y + dy);
 
        getsect(newx, newy, &sect);
-       if ((sect.sct_type == SCT_WATER) ||
-           (sect.sct_type == SCT_MOUNT) ||
-           (sect.sct_type == SCT_SANCT) ||
-           (sect.sct_type == SCT_WASTE) ||
-           (sect.sct_own != lp->lnd_own)) {
+       mobcost = lnd_mobcost(lp, &sect);
+       if (mobcost < 0
+           || sect.sct_type == SCT_MOUNT
+           || sect.sct_own != lp->lnd_own) {
            wu(0, lp->lnd_own, "%s %s,\nbut could not retreat to %s!\n",
               prland(lp),
               conditions[findcondition(code)].desc[orig],
@@ -507,30 +406,28 @@ retreat_land1(struct lndstr *lp, s_char code, int orig)
                putland(lp->lnd_uid, lp);
            return 0;
        }
-       mobcost = lnd_mobcost(lp, &sect, MOB_ROAD);
        lp->lnd_x = newx;
        lp->lnd_y = newy;
        lp->lnd_mobil -= mobcost;
-       if (stopping)
-           continue;
+       lp->lnd_mission = 0;
 
-       mines = sect.sct_mines;
-       if ((lcp->l_flags & L_ENGINEER) && mines > 0 &&
-           (sect.sct_oldown != lp->lnd_own)) {
+       mines = SCT_LANDMINES(&sect);
+       if (mines <= 0 || sect.sct_oldown == lp->lnd_own)
+           continue;
+       if (lcp->l_flags & L_ENGINEER) {
            max = lcp->l_item[I_SHELL];
            shells = lp->lnd_item[I_SHELL];
            for (m = 0; mines > 0 && m < 5; m++) {
                if (chance(0.66)) {
                    mines--;
-                   shells = min(max, shells + 1);
+                   shells = MIN(max, shells + 1);
                }
            }
            sect.sct_mines = mines;
            lp->lnd_item[I_SHELL] = shells;
            putsect(&sect);
        }
-       if (mines > 0 && (sect.sct_oldown != lp->lnd_own) &&
-           chance(DMINE_HITCHANCE(mines))) {
+       if (chance(DMINE_LHITCHANCE(mines))) {
            wu(0, lp->lnd_own,
               "%s %s,\nand hit a mine in %s while retreating!\n",
               prland(lp),
@@ -538,18 +435,16 @@ retreat_land1(struct lndstr *lp, s_char code, int orig)
               xyas(newx, newy, lp->lnd_own));
            nreport(lp->lnd_own, N_LHIT_MINE, 0, 1);
            m = MINE_LDAMAGE();
+           if (lcp->l_flags & L_ENGINEER)
+               m /= 2;
            landdamage(lp, m);
            mines--;
            sect.sct_mines = mines;
            putsect(&sect);
-           if (lp->lnd_effic < LAND_MINEFF)
-               time_to_stop = 1;
            if (!orig)
                putland(lp->lnd_uid, lp);
            return 0;
        }
-       if (time_to_stop)
-           stopping = 1;
     }
 
     if (orig) {