]> git.pond.sub.org Git - empserver/blobdiff - src/lib/commands/edit.c
edit: Make uninmplemented edit n fail instead of doing nothing
[empserver] / src / lib / commands / edit.c
index 28877ad7e58e4703efda557c85a277cb2e6288dc..9e282e60a17a3c51a3d27ad20ed66834d9c53237 100644 (file)
@@ -63,10 +63,7 @@ static int edit_plane(struct plnstr *, char *, char *);
 int
 edit(void)
 {
-    struct sctstr sect;
-    struct plnstr plane;
-    struct shpstr ship;
-    struct lndstr land;
+    union empobj_storage item;
     char *what;
     char *key, *ptr;
     int num;
@@ -89,7 +86,7 @@ edit(void)
            return RET_FAIL;
        if (!sarg_xy(ptr, &x, &y))
            return RET_FAIL;
-       if (!getsect(x, y, &sect))
+       if (!getsect(x, y, &item.sect))
            return RET_FAIL;
        break;
     case 'c':
@@ -100,24 +97,24 @@ edit(void)
     case 'p':
        if ((num = onearg(player->argp[2], "Plane number? ")) < 0)
            return RET_SYN;
-       if (!getplane(num, &plane))
+       if (!getplane(num, &item.plane))
            return RET_SYN;
        break;
     case 's':
        if ((num = onearg(player->argp[2], "Ship number? ")) < 0)
            return RET_SYN;
-       if (!getship(num, &ship))
+       if (!getship(num, &item.ship))
            return RET_SYN;
        break;
     case 'u':
        if ((num = onearg(player->argp[2], "Unit number? ")) < 0)
            return RET_SYN;
-       if (!getland(num, &land))
+       if (!getland(num, &item.land))
            return RET_SYN;
        break;
     case 'n':
        pr("Not implemented yet.\n");
-       break;
+       return RET_FAIL;
     default:
        pr("huh?\n");
        return RET_SYN;
@@ -125,20 +122,22 @@ edit(void)
     if (!player->argp[3]) {
        switch (ewhat) {
        case 'l':
-           print_sect(&sect);
+           print_sect(&item.sect);
            break;
        case 'c':
            print_nat(np);
            break;
        case 'p':
-           print_plane(&plane);
+           print_plane(&item.plane);
            break;
        case 's':
-           print_ship(&ship);
+           print_ship(&item.ship);
            break;
        case 'u':
-           print_land(&land);
+           print_land(&item.land);
            break;
+       default:
+           CANT_REACH();
        }
     }
     for (;;) {
@@ -152,26 +151,8 @@ edit(void)
            key = getin(buf, &ptr);
            if (!key)
                return RET_SYN;
-           if (!*key) {
-               switch (ewhat) {
-               case 'c':
-                   print_nat(np);
-                   break;
-               case 'l':
-                   print_sect(&sect);
-                   break;
-               case 's':
-                   print_ship(&ship);
-                   break;
-               case 'u':
-                   print_land(&land);
-                   break;
-               case 'p':
-                   print_plane(&plane);
-                   break;
-               }
+           if (!*key)
                return RET_OK;
-           }
        } else
            return RET_OK;
 
@@ -181,54 +162,43 @@ edit(void)
                return err;
            break;
        case 'l':
-           if (!check_sect_ok(&sect))
+           if (!check_sect_ok(&item.sect))
                return RET_FAIL;
-           if ((err = edit_sect(&sect, key, ptr)) != RET_OK)
+           if ((err = edit_sect(&item.sect, key, ptr)) != RET_OK)
                return err;
-           if (!putsect(&sect))
+           if (!putsect(&item.sect))
                return RET_FAIL;
            break;
        case 's':
-           if (!check_ship_ok(&ship))
+           if (!check_ship_ok(&item.ship))
                return RET_FAIL;
-           if ((err = edit_ship(&ship, key, ptr)) != RET_OK)
+           if ((err = edit_ship(&item.ship, key, ptr)) != RET_OK)
                return err;
-           if (!ef_ensure_space(EF_SHIP, ship.shp_uid, 50))
-               return RET_FAIL;
-           if (!putship(ship.shp_uid, &ship))
+           if (!putship(item.ship.shp_uid, &item.ship))
                return RET_FAIL;
            break;
        case 'u':
-           if (!check_land_ok(&land))
+           if (!check_land_ok(&item.land))
                return RET_FAIL;
-           if ((err = edit_land(&land, key, ptr)) != RET_OK)
+           if ((err = edit_land(&item.land, key, ptr)) != RET_OK)
                return err;
-           if (!ef_ensure_space(EF_LAND, land.lnd_uid, 50))
-               return RET_FAIL;
-           if (!putland(land.lnd_uid, &land))
+           if (!putland(item.land.lnd_uid, &item.land))
                return RET_FAIL;
            break;
        case 'p':
-           if (!check_plane_ok(&plane))
+           if (!check_plane_ok(&item.plane))
                return RET_FAIL;
-           if ((err = edit_plane(&plane, key, ptr)) != RET_OK)
+           if ((err = edit_plane(&item.plane, key, ptr)) != RET_OK)
                return err;
-           if (!ef_ensure_space(EF_PLANE, plane.pln_uid, 50))
-               return RET_FAIL;
-           if (!putplane(plane.pln_uid, &plane))
+           if (!putplane(item.plane.pln_uid, &item.plane))
                return RET_FAIL;
            break;
+       default:
+           CANT_REACH();
        }
     }
 }
 
-static void
-benefit(natid who, int goodness)
-{
-    if (opt_GODNEWS && getnatp(who)->nat_stat != STAT_GOD && goodness)
-       nreport(player->cnum, goodness > 0 ? N_AIDS : N_HURTS, who, 1);
-}
-
 static void
 noise(struct sctstr *sptr, char *name, int old, int new)
 {
@@ -630,107 +600,131 @@ edit_sect(struct sctstr *sect, char *key, char *p)
     return RET_OK;
 }
 
+static void
+edit_level(struct natstr *np, int lvl, char *name, char *p)
+{
+    float new = (float)atof(p);
+
+    new = MAX(0.0, new);
+    divine_nat_change(np, name,
+                     new != np->nat_level[lvl],
+                     (new > np->nat_level[lvl]) - (new < np->nat_level[lvl]),
+                     "from %.2f to %.2f", np->nat_level[lvl], new);
+    np->nat_level[lvl] = new;
+}
+
 static int
 edit_nat(struct natstr *np, char *key, char *p)
 {
     coord newx, newy;
     natid nat = np->nat_cnum;
     int arg = atoi(p);
-    float farg = (float)atof(p);
 
     switch (*key) {
     case 'n':
        if (!check_nat_name(p, nat))
            return RET_SYN;
-       pr("Country name changed from %s to %s\n", np->nat_cnam, p);
+       divine_nat_change(np, "Country name", strcmp(np->nat_cnam, p), 0,
+                         "from %s to %s", np->nat_cnam, p);
+       if (opt_GODNEWS)
+           nreport(player->cnum, N_NAME_CHNG, 0, 1);
        strcpy(np->nat_cnam, p);
        break;
     case 'r':
-       pr("Country representative changed from %s to %s\n",
-          np->nat_pnam, p);
+       divine_nat_change(np, "Country representative",
+               strncmp(p, np->nat_pnam, sizeof(np->nat_pnam) - 1), 0,
+               "from %s to %.*s",
+               np->nat_pnam, (int)sizeof(np->nat_pnam) - 1, p);
        strncpy(np->nat_pnam, p, sizeof(np->nat_pnam) - 1);
        break;
     case 't':
        arg = LIMIT_TO(arg, 0, USHRT_MAX);
+       divine_nat_change_quiet(np, "Number of unread telegrams",
+                               arg != np->nat_tgms,
+                               "from %d to %d", np->nat_tgms, arg);
        np->nat_tgms = arg;
        break;
     case 'b':
        arg = LIMIT_TO(arg, 0, max_btus);
-       pr("BTU's changed from %d to %d\n", np->nat_btu, arg);
+       divine_nat_change(np, "BTUs",
+                         arg != np->nat_btu, arg - np->nat_btu,
+                         "from %d to %d", np->nat_btu, arg);
        np->nat_btu = arg;
        break;
     case 'm':
        arg = LIMIT_TO(arg, 0, INT_MAX);
-       benefit(nat, arg - np->nat_reserve);
-       pr("Military reserves changed from %d to %d\n",
-          np->nat_reserve, arg);
-       if (arg == np->nat_reserve)
-           break;
-       if (nat != player->cnum)
-           wu(0, nat,
-              "Military reserves changed from %d to %d by an act of %s\n",
-              np->nat_reserve, arg, cname(player->cnum));
+       divine_nat_change(np, "Military reserves",
+                         arg != np->nat_reserve, arg - np->nat_reserve,
+                         "from %d to %d", np->nat_reserve, arg);
        np->nat_reserve = arg;
        break;
     case 'c':
        if (!sarg_xy(p, &newx, &newy))
            return RET_SYN;
-       pr("Capital coordinates changed from %s to %s\n",
-          xyas(np->nat_xcap, np->nat_ycap, player->cnum),
-          xyas(newx, newy, player->cnum));
+       if (newx == np->nat_xcap && newy == np->nat_ycap)
+           pr("Capital unchanged\n");
+       else {
+           pr("Capital moved from %s to %s\n",
+              xyas(np->nat_xcap, np->nat_ycap, player->cnum),
+              xyas(newx, newy, player->cnum));
+           if (nat != player->cnum)
+               wu(0, nat,
+                  "Capital moved from %s to %s by an act of %s!\n",
+                  xyas(np->nat_xcap, np->nat_ycap, nat),
+                  xyas(newx, newy, nat), cname(player->cnum));
+       }
        np->nat_xcap = newx;
        np->nat_ycap = newy;
        break;
     case 'o':
        if (!sarg_xy(p, &newx, &newy))
            return RET_SYN;
-       pr("Origin coordinates changed from %s to %s\n",
-          xyas(np->nat_xorg, np->nat_yorg, player->cnum),
-          xyas(newx, newy, player->cnum));
+       if (newx == np->nat_xorg && newy == np->nat_yorg)
+           pr("Origin unchanged\n");
+       else {
+           pr("Origin moved from %s to %s\n",
+              xyas(np->nat_xorg, np->nat_yorg, player->cnum),
+              xyas(newx, newy, player->cnum));
+           if (nat != player->cnum)
+               wu(0, nat,
+                  "Origin moved from %s to %s by an act of %s!\n",
+                  xyas(np->nat_xorg, np->nat_yorg, nat),
+                  xyas(newx, newy, nat), cname(player->cnum));
+       }
        np->nat_xorg = newx;
        np->nat_yorg = newy;
        break;
     case 's':
-       np->nat_stat = LIMIT_TO(arg, STAT_UNUSED, STAT_GOD);
+       arg = LIMIT_TO(arg, STAT_UNUSED, STAT_GOD);
+       divine_nat_change(np, "Status",
+                         (enum nat_status)arg != np->nat_stat,
+                         0, "to %s", nation_status[arg].name);
+       np->nat_stat = arg;
        break;
     case 'u':
        arg = LIMIT_TO(arg, 0, m_m_p_d * 60);
-       pr("Number of seconds used changed from %d to %d.\n",
-          np->nat_timeused, arg);
+       divine_nat_change(np, "Number of seconds used",
+                         arg != np->nat_timeused, arg - np->nat_timeused,
+                         "from %d to %d", np->nat_timeused, arg);
        np->nat_timeused = arg;
        break;
     case 'M':
-       pr("Money changed from %d to %d\n", np->nat_money, arg);
-       if (arg == np->nat_money)
-           break;
-       if (nat != player->cnum)
-           wu(0, nat, "Money changed from %d to %d by an act of %s\n",
-              np->nat_money, arg, cname(player->cnum));
+       divine_nat_change(np, "Money",
+                         arg != np->nat_money, arg - np->nat_money,
+                         "from %d to %d", np->nat_money, arg);
        np->nat_money = arg;
        break;
     case 'T':
-       farg = MAX(0.0, farg);
-       pr("Tech changed from %.2f to %.2f.\n",
-          np->nat_level[NAT_TLEV], farg);
-       np->nat_level[NAT_TLEV] = farg;
+       edit_level(np, NAT_TLEV, "Technology", p);
        break;
     case 'R':
-       farg = MAX(0.0, farg);
-       pr("Research changed from %.2f to %.2f.\n",
-          np->nat_level[NAT_RLEV], farg);
-       np->nat_level[NAT_RLEV] = farg;
+       edit_level(np, NAT_RLEV, "Research", p);
        break;
     case 'E':
-       farg = MAX(0.0, farg);
-       pr("Education changed from %.2f to %.2f.\n",
-          np->nat_level[NAT_ELEV], farg);
-       np->nat_level[NAT_ELEV] = farg;
+       edit_level(np, NAT_ELEV, "Education", p);
        break;
     case 'H':
-       farg = MAX(0.0, farg);
-       pr("Happiness changed from %.2f to %.2f.\n",
-          np->nat_level[NAT_HLEV], farg);
-       np->nat_level[NAT_HLEV] = farg;
+       edit_level(np, NAT_HLEV, "Happiness", p);
        break;
     default:
        pr("huh? (%s)\n", key);
@@ -742,14 +736,34 @@ edit_nat(struct natstr *np, char *key, char *p)
 
 static int
 edit_unit(struct empobj *unit, char *key, char *p,
-         int mineff, char *group_name)
+         int mineff, char *group_name, int on_carrier)
 {
     int arg = atoi(p);
     coord newx, newy;
+    union empobj_storage newunit;
+    char newgroup;
  
     switch (toupper(*key)) {
     case 'U':
+       if (arg < 0)
+           return RET_SYN;
+       if (arg == unit->uid) {
+           pr("%s unchanged\n", unit_nameof(unit));
+           break;
+       }
+       if (!ef_ensure_space(unit->ef_type, arg, 50)) {
+           pr("Can't copy to %s #%d\n", ef_nameof(unit->ef_type), arg);
+           return RET_FAIL;
+       }
+       pr("%s duplicated to (#%d)\n", unit_nameof(unit), arg);
        ef_set_uid(unit->ef_type, unit, arg);
+       if (get_empobj(unit->ef_type, arg, &newunit) && newunit.gen.own) {
+           pr("Replacing %s of %s\n",
+              unit_nameof(&newunit.gen), prnatid(newunit.gen.own));
+           report_god_takes("", unit_nameof(&newunit.gen),
+                            newunit.gen.own);
+       }
+       report_god_gives("", unit_nameof(unit), unit->own);
        break;
     case 'O':
        if (arg < 0 || arg >= MAXNOC)
@@ -766,28 +780,54 @@ edit_unit(struct empobj *unit, char *key, char *p,
     case 'L':
        if (!sarg_xy(p, &newx, &newy))
            return RET_SYN;
+       if (on_carrier && (newx != unit->x || newy != unit->y)) {
+           pr("Can't move %s while it's loaded\n", unit_nameof(unit));
+           return RET_FAIL;
+       }
+       divine_unit_change_quiet(unit, "Location",
+                                unit->own && unit->own != player->cnum,
+                                "from %s to %s",
+                                xyas(unit->x, unit->y, player->cnum),
+                                xyas(newx, newy, player->cnum));
+       if (unit->own && unit->own != player->cnum)
+           wu(0, unit->own,
+              "Location of %s changed from %s to %s by an act of %s!\n",
+              unit_nameof(unit),
+              xyas(unit->x, unit->y, unit->own),
+              xyas(newx, newy, unit->own),
+              cname(player->cnum));
        unit->x = newx;
        unit->y = newy;
        break;
     case 'E':
        arg = LIMIT_TO(arg, mineff, 100);
+       divine_unit_change(unit, "Efficiency",
+                          arg != unit->effic, arg - unit->effic,
+                          "from %d to %d", unit->effic, arg);
        unit->effic = arg;
        break;
     case 'M':
        arg = LIMIT_TO(arg, -127, 127);
+       divine_unit_change(unit, "Mobility",
+                          arg != unit->mobil, arg - unit->mobil,
+                          "from %d to %d", unit->mobil, arg);
        unit->mobil = arg;
        break;
     case 'F':
     case 'W':
     case 'A':
        if (p[0] == '~')
-           unit->group = 0;
+           newgroup = 0;
        else if (isalpha(p[0]))
-           unit->group = p[0];
+           newgroup = p[0];
        else {
            pr("%c: invalid %s\n", p[0], group_name);
            return RET_FAIL;
        }
+       divine_unit_change(unit, "Assignment", newgroup != unit->group, 0,
+                          "from %s %c to %c", group_name,
+                          unit->group ? unit->group : '~', p[0]);
+       unit->group = newgroup;
        break;
     default:
        CANT_REACH();
@@ -810,23 +850,38 @@ edit_ship(struct shpstr *ship, char *key, char *p)
     case 'M':
     case 'F':
        return edit_unit((struct empobj *)ship, key, p,
-                        SHIP_MINEFF, "fleet");
+                        SHIP_MINEFF, "fleet", 0);
     case 'T':
        arg = LIMIT_TO(arg, mcp->m_tech, SHRT_MAX);
+       divine_unit_change((struct empobj *)ship, "Tech level",
+                          arg != ship->shp_tech, arg - ship->shp_tech,
+                          "from %d to %d", ship->shp_tech, arg);
        shp_set_tech(ship, arg);
        break;
     case 'a':
        arg = LIMIT_TO(arg, 0, PLG_EXPOSED);
+       divine_unit_change_quiet((struct empobj *)ship, "Plague stage",
+                                arg != ship->shp_pstage,
+                                "from %d to %d", ship->shp_pstage, arg);
        ship->shp_pstage = arg;
        break;
     case 'b':
        arg = LIMIT_TO(arg, 0, 32767);
+       divine_unit_change_quiet((struct empobj *)ship, "Plague time",
+                                arg != ship->shp_ptime,
+                                "from %d to %d", ship->shp_ptime, arg);
        ship->shp_ptime = arg;
        break;
     case 'R':
+       divine_unit_change((struct empobj *)ship, "Retreat path",
+               strncmp(p, ship->shp_rpath, sizeof(ship->shp_rpath) - 1),
+               0, "from %s to %.*s",
+               ship->shp_rpath, (int)sizeof(ship->shp_rpath) - 1, p);
        strncpy(ship->shp_rpath, p, sizeof(ship->shp_rpath) - 1);
        break;
     case 'W':
+       divine_flag_change((struct empobj *)ship, "Retreat conditions",
+                          ship->shp_rflags, arg, retreat_flags);
        ship->shp_rflags = arg;
        break;
     case 'c':
@@ -874,36 +929,69 @@ edit_land(struct lndstr *land, char *key, char *p)
     case 'M':
     case 'a':
        return edit_unit((struct empobj *)land, key, p,
-                        LAND_MINEFF, "army");
+                        LAND_MINEFF, "army",
+                        land->lnd_ship >= 0 || land->lnd_land >= 0);
     case 't':
        arg = LIMIT_TO(arg, lcp->l_tech, SHRT_MAX);
+       divine_unit_change((struct empobj *)land, "Tech level",
+                          arg != land->lnd_tech, arg - land->lnd_tech,
+                          "from %d to %d", land->lnd_tech, arg);
        lnd_set_tech(land, arg);
        break;
     case 'F':
-       land->lnd_harden = LIMIT_TO(arg, 0, 127);
+       arg = LIMIT_TO(arg, 0, 127);
+       divine_unit_change((struct empobj *)land, "Fortification",
+                          arg != land->lnd_harden, arg - land->lnd_harden,
+                          "from %d to %d", land->lnd_harden, arg);
+       land->lnd_harden = arg;
        break;
     case 'S':
        if (arg < -1 || arg >= ef_nelem(EF_SHIP))
            return RET_SYN;
-       if (arg >= 0 && arg != land->lnd_ship)
+       if (arg == land->lnd_ship) {
+           pr("Ship of %s unchanged\n", prland(land));
+           break;
+       }
+       divine_unload((struct empobj *)land, EF_SHIP, land->lnd_ship);
+       if (arg >= 0) {
+           divine_unload((struct empobj *)land, EF_LAND, land->lnd_land);
            land->lnd_land = -1;
+       }
+       divine_load((struct empobj *)land, EF_SHIP, arg);
        land->lnd_ship = arg;
        break;
     case 'Y':
        if (arg < -1 || arg >= ef_nelem(EF_LAND))
            return RET_SYN;
-       if (arg >= 0 && arg != land->lnd_land)
+       if (arg == land->lnd_land) {
+           pr("Land unit of %s unchanged\n", prland(land));
+           break;
+       }
+       divine_unload((struct empobj *)land, EF_LAND, land->lnd_land);
+       if (arg >= 0) {
+           divine_unload((struct empobj *)land, EF_SHIP, land->lnd_ship);
            land->lnd_ship = -1;
+       }
+       divine_load((struct empobj *)land, EF_LAND, arg);
        land->lnd_land = arg;
        break;
     case 'Z':
        arg = LIMIT_TO(arg, 0, 100);
+       divine_unit_change((struct empobj *)land, "Retreat percentage",
+                          arg != land->lnd_retreat, 0,
+                          "from %d to %d", land->lnd_retreat, arg);
        land->lnd_retreat = arg;
        break;
     case 'R':
+       divine_unit_change((struct empobj *)land, "Retreat path",
+               strncmp(p, land->lnd_rpath, sizeof(land->lnd_rpath) - 1),
+               0, "from %s to %.*s",
+               land->lnd_rpath, (int)sizeof(land->lnd_rpath) - 1, p);
        strncpy(land->lnd_rpath, p, sizeof(land->lnd_rpath) - 1);
        break;
     case 'W':
+       divine_flag_change((struct empobj *)land, "Retreat condition",
+                          land->lnd_rflags, arg, retreat_flags);
        land->lnd_rflags = arg;
        break;
     case 'c':
@@ -950,30 +1038,55 @@ edit_plane(struct plnstr *plane, char *key, char *p)
     case 'm':
     case 'w':
        return edit_unit((struct empobj *)plane, key, p,
-                        PLANE_MINEFF, "wing");
+                        PLANE_MINEFF, "wing",
+                        plane->pln_ship >= 0 || plane->pln_land >= 0);
     case 't':
        arg = LIMIT_TO(arg, pcp->pl_tech, SHRT_MAX);
+       divine_unit_change((struct empobj *)plane, "Tech level",
+                          arg != plane->pln_tech, arg - plane->pln_tech,
+                          "from %d to %d", plane->pln_tech, arg);
        pln_set_tech(plane, arg);
        break;
     case 'r':
        arg = LIMIT_TO(arg, 0, pl_range(pcp, plane->pln_tech));
+       divine_unit_change((struct empobj *)plane, "Range",
+                          arg != plane->pln_range, 0,
+                          "from %d to %d", plane->pln_range, arg);
        plane->pln_range = (unsigned char)arg;
        break;
     case 's':
        if (arg < -1 || arg >= ef_nelem(EF_SHIP))
            return RET_SYN;
-       if (arg >= 0 && arg != plane->pln_ship)
+       if (arg == plane->pln_ship) {
+           pr("Ship of %s unchanged\n", prplane(plane));
+           break;
+       }
+       divine_unload((struct empobj *)plane, EF_SHIP, plane->pln_ship);
+       if (arg >= 0) {
+           divine_unload((struct empobj *)plane, EF_LAND, plane->pln_land);
            plane->pln_land = -1;
+       }
+       divine_load((struct empobj *)plane, EF_SHIP, arg);
        plane->pln_ship = arg;
        break;
     case 'y':
        if (arg < -1 || arg >= ef_nelem(EF_LAND))
            return RET_SYN;
-       if (arg >= 0 && arg != plane->pln_land)
+       if (arg == plane->pln_land) {
+           pr("Land unit of %s unchanged\n", prplane(plane));
+           break;
+       }
+       divine_unload((struct empobj *)plane, EF_LAND, plane->pln_land);
+       if (arg >= 0) {
+           divine_unload((struct empobj *)plane, EF_SHIP, plane->pln_ship);
            plane->pln_ship = -1;
+       }
+       divine_load((struct empobj *)plane, EF_LAND, arg);
        plane->pln_land = arg;
        break;
     case 'f':
+       divine_flag_change((struct empobj *)plane, "Flags",
+                          plane->pln_flags, arg, plane_flags);
        plane->pln_flags = arg;
        break;
     default: