/* * Dump @val prefixed with @sep to @xd, in machine readable format. * @val must be evaluated. * Return " ". */ static char * xdprval_nosym(struct xdstr *xd, struct valstr *val, char *sep) { if (CANT_HAPPEN(val->val_cat != NSC_VAL)) { xd->pr("%snil", sep); return " "; } switch (val->val_type) { case NSC_LONG: xd->pr("%s%ld", sep, val->val_as.lng); break; case NSC_DOUBLE: xd->pr("%s%#g", sep, val->val_as.dbl); break; case NSC_STRING: if (val->val_as.str.base) { xd->pr("%s\"", sep); xdpresc(xd, val->val_as.str.base, val->val_as.str.maxsz); xd->pr("\""); } else xd->pr("%snil", sep); break; default: CANT_REACH(); xd->pr("%snil", sep); } return " "; }
/* * Wipe orders and such from @unit. */ void unit_wipe_orders(struct empobj *unit) { struct shpstr *sp; struct plnstr *pp; struct lndstr *lp; unit->group = 0; unit->opx = unit->opy = 0; unit->mission = 0; unit->radius = 0; switch (unit->ef_type) { case EF_SHIP: sp = (struct shpstr *)unit; sp->shp_rflags = 0; sp->shp_rpath[0] = 0; break; case EF_PLANE: pp = (struct plnstr *)unit; pp->pln_range = pln_range_max(pp); break; case EF_LAND: lp = (struct lndstr *)unit; lp->lnd_retreat = morale_base; lp->lnd_rflags = 0; lp->lnd_rpath[0] = 0; break; case EF_NUKE: break; default: CANT_REACH(); } }
static void takeover_unit(struct empobj *unit, natid newown) { struct shpstr *sp; struct plnstr *pp; struct lndstr *lp; struct nukstr *np; int type; struct nstr_item ni; union empobj_storage cargo; unit->own = newown; if (opt_MARKET) trdswitchown(unit->ef_type, unit, newown); unit_wipe_orders(unit); switch (unit->ef_type) { case EF_SHIP: sp = (struct shpstr *)unit; sp->shp_off = 1; break; case EF_PLANE: pp = (struct plnstr *)unit; if (pp->pln_mobil > 0) pp->pln_mobil = 0; pp->pln_off = 1; break; case EF_LAND: lp = (struct lndstr *)unit; if (lp->lnd_mobil > 0) lp->lnd_mobil = 0; lp->lnd_off = 1; lp->lnd_harden = 0; break; case EF_NUKE: np = (struct nukstr *)unit; np->nuk_off = 1; break; default: CANT_REACH(); } put_empobj(unit->ef_type, unit->uid, unit); for (type = EF_PLANE; type <= EF_NUKE; type++) { snxtitem_cargo(&ni, type, unit->ef_type, unit->uid); while (nxtitem(&ni, &cargo)) { if (cargo.gen.own == newown) continue; if (type == EF_PLANE) cargo.plane.pln_effic = PLANE_MINEFF; takeover_unit(&cargo.gen, newown); } } }
static int cons_decline(struct ltcomstr *ltcp) { switch (ltcp->type) { case EF_LOAN: return loan_decline(ltcp); default: CANT_REACH(); return RET_FAIL; } }
static int cons_display(struct ltcomstr *ltcp) { switch (ltcp->type) { case EF_LOAN: return disloan(ltcp->num, <cp->u.l); default: CANT_REACH(); return 0; } }
/* * Post-processing after successful acceptance of loan. * Notify the press, and the folks involved. * (Weird spelling is to avoid accept(2)). */ static void accpt(struct ltcomstr *ltcp) { switch (ltcp->type) { case EF_LOAN: nreport(ltcp->proposer, N_MAKE_LOAN, player->cnum, 1); break; default: CANT_REACH(); } wu(0, ltcp->mailee, "%s #%d accepted by %s\n", ltcp->Name, ltcp->num, cname(player->cnum)); }
char * unit_nameof(struct empobj *gp) { switch (gp->ef_type) { case EF_SHIP: return prship((struct shpstr *)gp); case EF_PLANE: return prplane((struct plnstr *)gp); case EF_LAND: return prland((struct lndstr *)gp); case EF_NUKE: return prnuke((struct nukstr *)gp); } CANT_REACH(); return "The Beast #666"; }
double sector_mcost(struct sctstr *sp, int mobtype) { double base, cost; base = dchr[sp->sct_type].d_mob0; if (base < 0) return -1.0; if (mobtype == MOB_RAIL && opt_RAILWAYS) { if (!SCT_HAS_RAIL(sp)) return -1; mobtype = MOB_MARCH; } /* linear function in eff, d_mob0 at 0%, d_mob1 at 100% */ base += (dchr[sp->sct_type].d_mob1 - base) * sp->sct_effic / 100; if (CANT_HAPPEN(base < 0)) base = 0; if (mobtype == MOB_MOVE || mobtype == MOB_MARCH) { /* linear function in road, base at 0%, base/10 at 100% */ cost = base; if (intrchr[INT_ROAD].in_enable) cost -= base * 0.009 * sp->sct_road; } else if (mobtype == MOB_RAIL) { if (!intrchr[INT_RAIL].in_enable || sp->sct_rail <= 0) return -1.0; /* linear function in rail, base at 0%, base/100 at 100% */ cost = base - base * 0.0099 * sp->sct_rail; } else { CANT_REACH(); cost = base; } if (CANT_HAPPEN(cost < 0)) cost = 0; if (mobtype == MOB_MOVE) return MAX(cost, 0.001); if (sp->sct_own != sp->sct_oldown && sp->sct_mobil <= 0) /* slow down land units in newly taken sectors */ return cost + 0.2; return MAX(cost, 0.02); }
/* * Evaluate compiled conditions in array @np[@ncond]. * Return non-zero iff they are all true. * @ptr points to a context object of the type that was used to compile * the conditions. */ int nstr_exec(struct nscstr *np, int ncond, void *ptr) { int i, op, cmp; enum nsc_type optype; struct valstr lft, rgt; for (i = 0; i < ncond; ++i) { op = np[i].operator; optype = np[i].optype; if (np[i].lft.val_cat == NSC_NOCAT || np[i].rgt.val_cat == NSC_NOCAT) return 0; lft = np[i].lft; nstr_eval(&lft, player->cnum, ptr, optype); rgt = np[i].rgt; nstr_eval(&rgt, player->cnum, ptr, optype); if (CANT_HAPPEN(lft.val_type != optype || rgt.val_type != optype)) return 0; switch (optype) { case NSC_LONG: if (!EVAL(op, lft.val_as.lng, rgt.val_as.lng)) return 0; break; case NSC_DOUBLE: if (!EVAL(op, lft.val_as.dbl, rgt.val_as.dbl)) return 0; break; case NSC_STRING: cmp = strnncmp(lft.val_as.str.base, lft.val_as.str.maxsz, rgt.val_as.str.base, rgt.val_as.str.maxsz); if (!EVAL(op, cmp, 0)) return 0; break; default: CANT_REACH(); return 0; } } return 1; }
void WINAPI service_main(DWORD argc, LPTSTR *argv) { int sig; service_status.dwServiceType = SERVICE_WIN32; service_status.dwCurrentState = SERVICE_START_PENDING; service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; service_status.dwWin32ExitCode = 0; service_status.dwServiceSpecificExitCode = 0; service_status.dwCheckPoint = 0; service_status.dwWaitHint = 0; service_status_handle = RegisterServiceCtrlHandler( DEFAULT_SERVICE_NAME, service_ctrl_handler); if (service_status_handle == (SERVICE_STATUS_HANDLE)0) { logerror("RegisterServiceCtrlHandler failed %lu\n", GetLastError()); finish_server(); return; } start_server(0); /* Initialization complete - report running status. */ service_status.dwCurrentState = SERVICE_RUNNING; service_status.dwCheckPoint = 0; service_status.dwWaitHint = 0; if (!SetServiceStatus (service_status_handle, &service_status)) { logerror("SetServiceStatus error %ld\n", GetLastError()); } sig = empth_wait_for_signal(); shutdwn(sig); CANT_REACH(); finish_server(); }
int cons(void) { int rv; struct ltcomstr ltc; rv = cons_choose(<c); if (rv != RET_OK) return rv; switch (ltc.op) { case 'a': return cons_accept(<c); case 'd': return cons_decline(<c); case 'p': return cons_postpone(<c); default: CANT_REACH(); return RET_SYN; } }
int powe(void) { struct natstr *natp; int i; time_t pow_time; struct nstr_item ni; int save = 1; int num = MAXNOC; int power_generated = 0; struct natstr nat; struct powstr powbuf[MAXNOC]; int targets[MAXNOC]; int use_targets = 0; int no_numbers = 0; memset(targets, 0, sizeof(targets)); i = 1; if (player->argp[1]) { switch (player->argp[1][0]) { case 'u': if (player->god) save = 0; /* fall through */ case 'n': i++; natp = getnatp(player->cnum); if (natp->nat_btu < 1) pr("\n Insufficient BTUs, using the last report.\n\n"); else if (opt_AUTO_POWER && save) pr("\n power new is disabled, using the last report.\n\n"); else { gen_power(powbuf, save); pow_time = time(NULL); power_generated = 1; } } } if (player->argp[i]) { if (player->argp[i][0] == 'c') { if (!snxtitem(&ni, EF_NATION, player->argp[i + 1], NULL)) return RET_SYN; while (nxtitem(&ni, &nat)) { if (nat.nat_stat == STAT_UNUSED) continue; if (!player->god && nat.nat_stat != STAT_ACTIVE) continue; targets[nat.nat_cnum] = 1; } use_targets = 1; } else num = atoi(player->argp[i]); } if (num < 0) { if (!player->god) return RET_SYN; num = -num; no_numbers = 1; } if (!power_generated) { pow_time = ef_mtime(EF_POWER); snxtitem_all(&ni, EF_POWER); if (!nxtitem(&ni, &powbuf[0])) { pr("Power for this game has not been built yet.%s\n", opt_AUTO_POWER ? "" : " Type 'power new' to build it."); return RET_FAIL; } for (i = 1; i < MAXNOC; i++) { if (!nxtitem(&ni, &powbuf[i])) { CANT_REACH(); memset(&powbuf[i], 0, sizeof(powbuf[i])); } } } pr(" - = [ Empire Power Report ] = -\n"); pr(" as of %s\n sects eff civ", ctime(&pow_time)); pr(" mil shell gun pet iron dust oil pln ship unit money\n"); for (i = 1; i < MAXNOC && num > 0; i++) { if (opt_HIDDEN) { if (!player->god && powbuf[i].p_nation != player->cnum) continue; } if (use_targets && !targets[powbuf[i].p_nation]) continue; if (!use_targets && powbuf[i].p_power <= 0.0) continue; prpower(cname(powbuf[i].p_nation), &powbuf[i], powbuf[i].p_nation != player->cnum && !player->god); if (player->god && !no_numbers) pr("%9.2f\n", powbuf[i].p_power); num--; } if (!opt_HIDDEN || player->god) { pr(" ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----\n"); prpower("worldwide", &powbuf[0], !player->god); pr("\n"); } return RET_OK; }
int nxtitem(struct nstr_item *np, void *ptr) { struct empobj *gp; int selected; if (np->sel == NS_UNDEF) return 0; gp = (struct empobj *)ptr; do { if (np->sel == NS_LIST) { np->index++; if (np->index >= np->size) return 0; np->cur = np->list[np->index]; } else if (np->sel == NS_CARGO) { if (np->next < 0) return 0; np->cur = np->next; np->next = unit_cargo_next(np->type, np->next); } else { np->cur++; } if (!ef_read(np->type, np->cur, ptr)) return 0; selected = 1; switch (np->sel) { case NS_LIST: case NS_CARGO: case NS_ALL: break; case NS_DIST: if (CANT_HAPPEN(!(ef_flags(np->type) & EFF_XY))) return 0; if (!xyinrange(gp->x, gp->y, &np->range)) { selected = 0; break; } np->curdist = mapdist(gp->x, gp->y, np->cx, np->cy); if (np->curdist > np->dist) selected = 0; break; case NS_AREA: if (CANT_HAPPEN(!(ef_flags(np->type) & EFF_XY))) return 0; if (!xyinrange(gp->x, gp->y, &np->range)) selected = 0; break; case NS_XY: if (CANT_HAPPEN(!(ef_flags(np->type) & EFF_XY))) return 0; if (xnorm(gp->x) != np->cx || ynorm(gp->y) != np->cy) selected = 0; break; case NS_GROUP: if (CANT_HAPPEN(!(ef_flags(np->type) & EFF_GROUP))) return 0; if (np->group != gp->group) selected = 0; break; default: CANT_REACH(); return 0; } if (selected && np->ncond) { /* nstr_exec is expensive, so we do it last */ if (!nstr_exec(np->cond, np->ncond, ptr)) selected = 0; } } while (!selected); return 1; }
int pln_airbase_ok(struct plnstr *pp, int oneway, int noisy) { struct shpstr ship; struct lndstr land; struct sctstr sect; struct plchrstr *pcp = plchr + pp->pln_type; if (CANT_HAPPEN(noisy && pp->pln_own != player->cnum)) noisy = 0; if (pp->pln_ship >= 0) { /* ship: needs to be own or allied, efficient */ if (!getship(pp->pln_ship, &ship)) { CANT_REACH(); return 0; } if (relations_with(ship.shp_own, pp->pln_own) != ALLIED) { if (noisy) pr("(note) An ally does not own the ship %s is on\n", prplane(pp)); return 0; } if (!(carrier_planes(&ship, pcp->pl_flags & P_M) & pcp->pl_flags)) return 0; } else if (pp->pln_land >= 0) { /* land: needs to be own or allied, efficient, not embarked */ if (!getland(pp->pln_land, &land)) { CANT_REACH(); return 0; } if (relations_with(land.lnd_own, pp->pln_own) != ALLIED) { if (noisy) pr("(note) An ally does not own the unit %s is on\n", prplane(pp)); return 0; } if (land.lnd_effic < LND_AIROPS_EFF || !(pcp->pl_flags & P_E)) return 0; if (land.lnd_ship >= 0 || land.lnd_land >= 0) return 0; } else { /* sector: needs to be own or allied, efficient airfield */ if (!getsect(pp->pln_x, pp->pln_y, §)) { CANT_REACH(); return 0; } if (relations_with(sect.sct_own, pp->pln_own) != ALLIED) { if (noisy) pr("(note) An ally does not own the sector %s is in\n", prplane(pp)); return 0; } /* need airfield unless VTOL */ if ((pcp->pl_flags & P_V) == 0) { if (sect.sct_type != SCT_AIRPT) { if (noisy) pr("%s not at airport\n", prplane(pp)); return 0; } if (sect.sct_effic < 40) { if (noisy) pr("%s is not 40%% efficient, %s can't take off from there.\n", xyas(sect.sct_x, sect.sct_y, player->cnum), prplane(pp)); return 0; } if (!oneway && sect.sct_effic < 60) { if (noisy) pr("%s is not 60%% efficient, %s can't land there.\n", xyas(sect.sct_x, sect.sct_y, player->cnum), prplane(pp)); return 0; } } } return 1; }
/*ARGSUSED*/ void player_accept(void *unused) { static int conn_cnt; struct sockaddr *sap; struct player *np; socklen_t len; const char *p; int ns; int set = 1; int stacksize; char buf[128]; #ifdef RESOLVE_IPADDRESS struct hostent *hostp; #endif /* auto sockaddr_storage would be simpler, but less portable */ sap = malloc(player_addrlen); len = player_addrlen; if (getsockname(player_socket, sap, &len)) { logerror("getsockname() failed: %s", strerror(errno)); p = NULL; } else { p = sockaddr_ntop(sap, buf, sizeof(buf)); CANT_HAPPEN(!p); } logerror("Listening on %s", p ? buf : "unknown address"); while (1) { empth_select(player_socket, EMPTH_FD_READ, NULL); len = player_addrlen; ns = accept(player_socket, sap, &len); /* FIXME accept() can block on some systems (RST after select() reports ready) */ if (ns < 0) { logerror("new socket accept"); continue; } (void)setsockopt(ns, SOL_SOCKET, SO_KEEPALIVE, &set, sizeof(set)); np = player_new(ns); if (!np) { logerror("can't create player for fd %d", ns); close(ns); continue; } if (!sockaddr_ntop(sap, np->hostaddr, sizeof(np->hostaddr))) { CANT_REACH(); player_delete(np); continue; } logerror("Connect from %s", np->hostaddr); #ifdef RESOLVE_IPADDRESS hostp = gethostbyaddr(inaddr, player_addrlen, sap->sa_family); if (NULL != hostp) strcpy(np->hostname, hostp->h_name); #endif /* RESOLVE_IPADDRESS */ /* FIXME ancient black magic; figure out true stack need */ stacksize = 100000 /* budget */ + MAX(WORLD_SZ() * sizeof(int) * 7, /* power */ MAXNOC * sizeof(struct powstr)); sprintf(buf, "Conn%d", conn_cnt++); empth_create(player_login, stacksize, 0, buf, np); } }
/* * Execute command named by player->argp[0]. * BUF is the raw UTF-8 command line. It should have been passed to * parse() to set up player->argp. * If REDIR is not null, it's the command's redirection, in UTF-8. * Return -1 if the command is not unique or doesn't exist, else 0. */ int dispatch(char *buf, char *redir) { struct natstr *np; struct cmndstr *command; int cmd; cmd = comtch(player->argp[0], player_coms, player->nstat); if (cmd < 0) { if (cmd == M_NOTUNIQUE) pr("Command \"%s\" is ambiguous -- ", player->argp[0]); else if (cmd == M_IGNORE) return 0; else pr("\"%s\" is not a legal command\n", player->argp[0]); return -1; } command = &player_coms[cmd]; np = getnatp(player->cnum); if (np->nat_btu < command->c_cost && command->c_cost > 0) { if (player->god || opt_BLITZ) np->nat_btu = max_btus; else { pr("You don't have the BTU's, bozo\n"); return 0; } } if (!command->c_addr) { pr("Command not implemented\n"); return 0; } player->may_sleep = command->c_flags & C_MOD ? PLAYER_SLEEP_ON_INPUT : PLAYER_SLEEP_FREELY; player->command = command; empth_rwlock_rdlock(update_lock); if (redir) { prredir(redir); uprnf(buf); pr("\n"); } journal_command(command->c_form); switch (command->c_addr()) { case RET_OK: player->btused += command->c_cost; break; case RET_FAIL: pr("command failed\n"); player->btused += command->c_cost; break; case RET_SYN: pr("Usage: %s\n", command->c_form); break; default: CANT_REACH(); break; } empth_rwlock_unlock(update_lock); player->command = NULL; if (player->may_sleep != PLAYER_SLEEP_NEVER || !io_eof(player->iop)) player->may_sleep = PLAYER_SLEEP_FREELY; /* else we're being kicked out */ return 0; }
int pln_equip(struct plist *plp, struct ichrstr *ip, char mission) { struct plchrstr *pcp; struct plnstr *pp; int load, needed; struct lndstr land; struct shpstr ship; struct sctstr sect; i_type itype; short *item; int own; int abandon_needed; pp = &plp->plane; pcp = plp->pcp; if (pp->pln_ship >= 0) { getship(pp->pln_ship, &ship); plp->pstage = ship.shp_pstage; item = ship.shp_item; own = ship.shp_own; } else if (pp->pln_land >= 0) { getland(pp->pln_land, &land); plp->pstage = land.lnd_pstage; item = land.lnd_item; own = land.lnd_own; } else { getsect(pp->pln_x, pp->pln_y, §); plp->pstage = sect.sct_pstage; item = sect.sct_item; own = sect.sct_oldown; } if (pcp->pl_fuel > item[I_PETROL]) { pr("%s not enough petrol there!\n", prplane(pp)); return -1; } item[I_PETROL] -= pcp->pl_fuel; load = pln_load(pp); itype = I_NONE; switch (mission) { case 's': /* strategic bomb */ case 'p': /* pinpoint bomb */ itype = I_SHELL; break; case 't': /* transport */ if (!(pcp->pl_flags & P_C) || !ip) break; itype = ip->i_uid; load *= 2; break; case 'm': /* mine */ if ((pcp->pl_flags & P_MINE) == 0) break; itype = I_SHELL; load *= 2; break; case 'd': /* drop */ if (!(pcp->pl_flags & P_C) || CANT_HAPPEN(!ip)) break; itype = ip->i_uid; if (pcp->pl_flags & P_V) load *= 2; break; case 'a': /* paradrop */ if (!(pcp->pl_flags & P_P)) break; itype = I_MILIT; if (pcp->pl_flags & P_V) load *= 2; break; case 'r': /* reconnaissance */ case 'e': /* escort */ load = 0; break; case 'i': /* missile interception */ if (CANT_HAPPEN(!(pcp->pl_flags & P_M) || !(pcp->pl_flags & (P_N | P_O)))) break; if (load) itype = I_SHELL; break; default: CANT_REACH(); load = 0; } if (itype != I_NONE) { needed = load / ichr[itype].i_lbs; if (needed <= 0) { pr("%s can't contribute to mission\n", prplane(pp)); return -1; } if (nuk_on_plane(pp) >= 0) { if (mission == 's' || mission == 't') needed = 0; else { pr("%s can't fly this mission" " while it is carrying a nuclear weapon", prplane(pp)); return -1; } } if (itype == I_CIVIL && pp->pln_own != own) { pr("You don't control those civilians!\n"); return -1; } #if 0 /* Supply is broken somewhere, so don't use it for now */ if (itype == I_SHELL && item[itype] < needed) item[itype] += supply_commod(plp->plane.pln_own, plp->plane.pln_x, plp->plane.pln_y, I_SHELL, needed); #endif if (pp->pln_ship >= 0 || pp->pln_land >= 0) abandon_needed = 0; else abandon_needed = !!would_abandon(§, itype, needed, NULL); if (item[itype] < needed + abandon_needed) { pr("Not enough %s for %s\n", ichr[itype].i_name, prplane(pp)); return -1; } item[itype] -= needed; plp->load = needed; } if (pp->pln_ship >= 0) { if (pp->pln_own != ship.shp_own) { wu(0, ship.shp_own, "%s %s prepares for takeoff from ship %s\n", cname(pp->pln_own), prplane(pp), prship(&ship)); } putship(ship.shp_uid, &ship); } else if (pp->pln_land >= 0) { if (pp->pln_own != land.lnd_own) { wu(0, land.lnd_own, "%s %s prepares for takeoff from unit %s\n", cname(pp->pln_own), prplane(pp), prland(&land)); } putland(land.lnd_uid, &land); } else { if (pp->pln_own != sect.sct_own) { wu(0, sect.sct_own, "%s %s prepares for takeoff from %s\n", cname(pp->pln_own), prplane(pp), xyas(sect.sct_x, sect.sct_y, sect.sct_own)); } putsect(§); } return 0; }
int edit(void) { union empobj_storage item; char *what; struct nstr_item ni; char *key, *ptr; struct natstr *np; int type, arg_index, ret; char buf[1024]; what = getstarg(player->argp[1], "Edit what (country, land, ship, plane, nuke, unit)? ", buf); if (!what) return RET_SYN; switch (what[0]) { case 'l': type = EF_SECTOR; break; case 'p': type = EF_PLANE; break; case 's': type = EF_SHIP; break; case 'u': type = EF_LAND; break; case 'n': type = EF_NUKE; break; case 'c': type = EF_NATION; break; default: pr("huh?\n"); return RET_SYN; } if (!snxtitem(&ni, type, player->argp[2], NULL)) return RET_SYN; while (nxtitem(&ni, &item)) { if (!player->argp[3]) { switch (type) { case EF_SECTOR: print_sect(&item.sect); break; case EF_SHIP: print_ship(&item.ship); break; case EF_PLANE: print_plane(&item.plane); break; case EF_LAND: print_land(&item.land); break; case EF_NUKE: print_nuke(&item.nuke); break; case EF_NATION: print_nat(&item.nat); break; default: CANT_REACH(); } } arg_index = 3; for (;;) { if (player->argp[arg_index]) { if (player->argp[arg_index+1]) { key = player->argp[arg_index++]; ptr = player->argp[arg_index++]; } else return RET_SYN; } else if (arg_index == 3) { key = getin(buf, &ptr); if (!key) return RET_SYN; if (!*key) break; } else break; if (!check_obj_ok(&item.gen)) return RET_FAIL; switch (type) { case EF_NATION: /* * edit_nat() may update the edited country by sending * it bulletins. Writing back item.nat would trigger * a seqno mismatch oops. Workaround: edit in-place. */ np = getnatp(item.nat.nat_cnum); ret = edit_nat(np, key, ptr); if (ret != RET_OK) return ret; if (!putnat(np)) return RET_FAIL; item.nat = *np; continue; case EF_SECTOR: ret = edit_sect(&item.sect, key, ptr); break; case EF_SHIP: ret = edit_ship(&item.ship, key, ptr); break; case EF_LAND: ret = edit_land(&item.land, key, ptr); break; case EF_PLANE: ret = edit_plane(&item.plane, key, ptr); break; case EF_NUKE: ret = edit_nuke(&item.nuke, key, ptr); break; default: CANT_REACH(); } if (ret != RET_OK) return ret; if (!put_empobj(type, item.gen.uid, &item.gen)) return RET_FAIL; } } return RET_OK; }