/* * Accept a loan. If the offering country has too little money, * leave him $100 left and offer the rest. Return RET_OK on * success, anything else on error. */ static int loan_accept(struct ltcomstr *ltcp) { struct lonstr *lp; struct natstr *lender; struct nstr_item nstr; struct lonstr loan; lp = <cp->u.l; if (ltcp->proposee != player->cnum) { pr("%s %d is still pending.\n", ltcp->Name, ltcp->num); return RET_OK; } if (!getloan(ltcp->num, lp)) { logerror("loan_accept: can't read loan"); pr("can't read loan; get help!\n"); return RET_FAIL; } if (lp->l_status == LS_FREE) { /* other guy retratcted already */ late(ltcp); return RET_OK; } if (lp->l_status == LS_SIGNED) { /* already signed somehow */ prev_signed(ltcp); return RET_OK; } /* check to see if a loan already exists */ snxtitem_all(&nstr, EF_LOAN); while (nxtitem(&nstr, &loan)) { if (loan.l_status == LS_SIGNED && loan.l_lonee == lp->l_loner && (loan.l_loner == lp->l_lonee)) { pr("He already owes you money - make him repay his loan!\n"); return RET_OK; } } lender = getnatp(ltcp->proposer); if (lender->nat_money < lp->l_amtdue) { /* other guy is poor */ lp->l_amtdue = lender->nat_money - 100; pr("%s no longer has the funds.\n", cname(ltcp->proposer)); if (lp->l_amtdue <= 0) return RET_FAIL; pr("You may borrow $%d at the same terms.\n", lp->l_amtdue); } lender->nat_money -= lp->l_amtdue; putnat(lender); player->dolcost -= lp->l_amtdue; lp->l_amtpaid = 0; (void)time(&lp->l_lastpay); lp->l_duedate = lp->l_ldur * SECS_PER_DAY + lp->l_lastpay; lp->l_status = LS_SIGNED; if (!putloan(ltcp->num, lp)) { pr("Problem writing lp->to disk; get help!\n"); return RET_FAIL; } accpt(ltcp); pr("You are now $%d richer (sort of).\n", lp->l_amtdue); return RET_OK; }
void setrej(natid us, natid them, int how, int what) { struct natstr *np = getnatp(us); if (CANT_HAPPEN(!np)) return; putreject(np, them, how, what); putnat(np); }
void setcont(natid us, natid them, int contact) { struct natstr *np = getnatp(us); if (CANT_HAPPEN(!np)) return; putcontact(np, them, contact); putnat(np); }
void enforce_minimum_session_time(void) { struct natstr *natp = getnatp(player->cnum); time_t dt = natp->nat_last_logout - natp->nat_last_login; if (dt > seconds_since_midnight(natp->nat_last_logout)) dt = seconds_since_midnight(natp->nat_last_logout); if (dt < 15) natp->nat_timeused += 15 - dt; putnat(natp); }
void update_timeused_login(time_t now) { struct natstr *natp = getnatp(player->cnum); time_t midnight_secs = seconds_since_midnight(now); if (now - natp->nat_last_logout > midnight_secs) { natp->nat_timeused = 0; putnat(natp); } player->lasttime = now; }
void update_timeused(time_t now) { struct natstr *natp = getnatp(player->cnum); time_t midnight_secs = seconds_since_midnight(now); time_t dt = now - player->lasttime; if (dt > midnight_secs) natp->nat_timeused = midnight_secs; else natp->nat_timeused += dt; player->lasttime = now; putnat(natp); }
int orig(void) { char *p; coord x, y; char buf[1024]; int cnum; struct natstr *np; p = getstarg(player->argp[1], "New origin (sector or country) : ", buf); if (!p || !*p) return RET_SYN; if (!isalpha(*p) && strchr(p, ',')) { /* sector */ if (!sarg_xy(p, &x, &y)) { pr("Bad sector designation.\n"); return RET_SYN; } } else if (*p == '~') { /* reset */ if (!player->god) { pr("Only deities can reset their origin.\n"); return RET_FAIL; } x = y = 0; } else { /* country */ cnum = natarg(p, NULL); if (!(np = getnatp(cnum))) return RET_SYN; if (!player->god && relations_with(cnum, player->cnum) != ALLIED) { pr("Country %s is not allied with you!\n", np->nat_cnam); return RET_FAIL; } x = np->nat_xorg; y = np->nat_yorg; } pr("Origin at %s (old system) is now at 0,0 (new system).\n", xyas(x, y, player->cnum)); np = getnatp(player->cnum); np->nat_xorg = x; np->nat_yorg = y; putnat(np); return RET_OK; }
int chan(void) { char *p; int charge; int btucost; char buf[1024]; struct natstr *us; p = getstarg(player->argp[1], "country name or representative? ", buf); if (!p) return RET_SYN; us = getnatp(player->cnum); switch (*p) { case 'n': case 'c': charge = 0; btucost = 0; if (us->nat_stat == STAT_ACTIVE) { if (opt_BLITZ == 0) { if (us->nat_btu < 254) { pr("You need 254 btus to change your country name!\n"); return RET_FAIL; } pr("This command costs 254 BTU's and 10%% of your money.\n"); if (!confirm("Are you sure you want to do this? ")) return RET_FAIL; btucost = 254; if (us->nat_money <= 0) charge = 0; else charge = us->nat_money / 10; } } p = getstarg(player->argp[2], "New country name -- ", buf); if (!p) return RET_SYN; if (!check_nat_name(p, player->cnum)) return RET_FAIL; player->dolcost += charge; player->btused += btucost; strcpy(us->nat_cnam, p); putnat(us); nreport(player->cnum, N_NAME_CHNG, 0, 1); break; case 'p': case 'r': pr("(note: these are stored in plain text.)\n"); p = getstarg(player->argp[2], "New representative name -- ", buf); if (!p) return RET_SYN; p[sizeof(us->nat_pnam) - 1] = 0; strcpy(us->nat_pnam, p); putnat(us); break; default: pr("Only \"country\" or \"representative\" can change.\n"); return RET_SYN; } return RET_OK; }
int repa(void) { struct lonstr loan; struct natstr *natp; struct natstr *loaner; int loan_num; int payment; int newdue; char *cp; time_t now; char buf[1024]; if (!opt_LOANS) { pr("Loans are not enabled.\n"); return RET_FAIL; } natp = getnatp(player->cnum); cp = getstarg(player->argp[1], "Repay loan #? ", buf); if (!cp) return RET_SYN; loan_num = atoi(cp); if (loan_num < 0) return RET_SYN; if (!getloan(loan_num, &loan) || loan.l_lonee != player->cnum || loan.l_status != LS_SIGNED) { pr("You don't owe anything on that loan.\n"); return RET_FAIL; } if (!(cp = getstarg(player->argp[2], "amount? ", buf))) return RET_SYN; if (!check_loan_ok(&loan)) return RET_FAIL; payment = atoi(cp); if (payment <= 0) return RET_SYN; newdue = (int)ceil(loan_owed(&loan, time(&now)) - payment); if (newdue < 0) { pr("You don't owe that much.\n"); return RET_FAIL; } if (natp->nat_money < payment) { pr("You only have $%d.\n", natp->nat_money); return RET_FAIL; } player->dolcost += payment; loaner = getnatp(loan.l_loner); loaner->nat_money += payment; putnat(loaner); loan.l_lastpay = now; if (newdue == 0) { wu(0, loan.l_loner, "Country #%d paid off loan #%d with $%d\n", player->cnum, loan_num, payment); nreport(player->cnum, N_REPAY_LOAN, loan.l_loner, 1); loan.l_status = LS_FREE; loan.l_ldur = 0; pr("Congratulations, you've paid off the loan!\n"); } else { wu(0, loan.l_loner, "Country #%d paid $%d on loan %d\n", player->cnum, payment, loan_num); loan.l_amtdue = newdue; loan.l_amtpaid += payment; } if (!putloan(loan_num, &loan)) { logerror("repa: can't write loan"); pr("Can't save loan; get help!\n"); return RET_FAIL; } return RET_OK; }
void setrel(natid us, natid them, int rel) { struct natstr *mynp = getnatp(us); struct natstr *themnp = getnatp(them); int oldrel; char *whichway; int n_up = 0; int n_down = 0; char *addendum = NULL; if (CANT_HAPPEN(rel < AT_WAR)) rel = AT_WAR; if (CANT_HAPPEN(rel > ALLIED)) rel = ALLIED; if (CANT_HAPPEN(!mynp || !themnp)) return; if (us == them) return; oldrel = relations_with(us, them); if (oldrel == rel) return; if (rel > oldrel) whichway = "upgraded"; else whichway = "downgraded"; if (rel == ALLIED) { addendum = "Congratulations!"; n_up = N_DECL_ALLY; } else if (rel == FRIENDLY) { n_up = N_UP_FRIENDLY; n_down = N_DOWN_FRIENDLY; } else if (rel == NEUTRAL) { n_up = N_UP_NEUTRAL; n_down = N_DOWN_NEUTRAL; } else if (rel == HOSTILE) { addendum = "Another cold war..."; n_up = N_UP_HOSTILE; n_down = N_DOWN_HOSTILE; } else if (rel < HOSTILE) { addendum = "Declaration made (give 'em hell)."; n_down = N_DECL_WAR; } if (addendum && us == player->cnum && !update_running) pr("%s\n", addendum); mpr(us, "Diplomatic relations with %s %s to \"%s\".\n", cname(them), whichway, relates[rel]); if (!(getrejects(us, themnp) & REJ_TELE)) mpr(them, "Country %s has %s their relations with you to \"%s\"!\n", prnat(mynp), whichway, relates[rel]); putrel(mynp, them, rel); putnat(mynp); if (!player->god) { if (oldrel == ALLIED) nreport(us, N_DIS_ALLY, them, 1); else if (oldrel < HOSTILE && rel >= HOSTILE) nreport(us, N_DIS_WAR, them, 1); if (rel > oldrel) nreport(us, n_up, them, 1); else nreport(us, n_down, them, 1); } if (opt_HIDDEN) setcont(them, us, FOUND_TELE); }
int check_trade(void) { int n; struct natstr *natp; struct trdstr trade; union empobj_storage tg; time_t now; int price; int saveid; natid seller; for (n = 0; gettrade(n, &trade); n++) { if (trade.trd_unitid < 0) continue; if (!trade_getitem(&trade, &tg)) continue; if (tg.gen.own == 0) { trade.trd_owner = 0; trade.trd_unitid = -1; puttrade(n, &trade); continue; } if (tg.gen.own != trade.trd_owner) { logerror("Something weird, tg.gen.own != trade.trd_owner!\n"); trade.trd_owner = 0; trade.trd_unitid = -1; puttrade(n, &trade); continue; } if (trade.trd_owner == trade.trd_maxbidder) continue; (void)time(&now); if (trade.trd_markettime + TRADE_DELAY > now) continue; saveid = trade.trd_unitid; seller = trade.trd_owner; trade.trd_owner = 0; trade.trd_unitid = -1; if (!puttrade(n, &trade)) { logerror("Couldn't save trade after purchase; get help!\n"); continue; } price = trade.trd_price; natp = getnatp(trade.trd_maxbidder); if (natp->nat_money < price) { nreport(trade.trd_maxbidder, N_WELCH_DEAL, seller, 1); wu(0, seller, "%s tried to buy a %s #%d from you for $%.2f\n", cname(trade.trd_maxbidder), trade_nameof(&trade, &tg.gen), saveid, price * tradetax); wu(0, seller, " but couldn't afford it.\n"); wu(0, seller, " Your item was taken off the market.\n"); wu(0, trade.trd_maxbidder, "You tried to buy %s #%d from %s for $%d\n", trade_nameof(&trade, &tg.gen), saveid, cname(seller), price); wu(0, trade.trd_maxbidder, "but couldn't afford it.\n"); continue; } /* If we get this far, the sale will go through. */ natp->nat_money -= price; putnat(natp); natp = getnatp(seller); natp->nat_money += roundavg(price * tradetax); putnat(natp); switch (trade.trd_type) { case EF_NUKE: tg.nuke.nuk_x = trade.trd_x; tg.nuke.nuk_y = trade.trd_y; tg.nuke.nuk_plane = -1; break; case EF_PLANE: if (!pln_is_in_orbit(&tg.plane)) { tg.plane.pln_x = trade.trd_x; tg.plane.pln_y = trade.trd_y; } if (opt_MOB_ACCESS) { tg.plane.pln_mobil = -(etu_per_update / sect_mob_neg_factor); game_tick_to_now(&tg.plane.pln_access); } else { tg.plane.pln_mobil = 0; } tg.plane.pln_harden = 0; tg.plane.pln_ship = -1; tg.plane.pln_land = -1; break; case EF_SHIP: break; case EF_LAND: tg.land.lnd_x = trade.trd_x; tg.land.lnd_y = trade.trd_y; if (opt_MOB_ACCESS) { tg.land.lnd_mobil = -(etu_per_update / sect_mob_neg_factor); game_tick_to_now(&tg.land.lnd_access); } else { tg.land.lnd_mobil = 0; } tg.land.lnd_harden = 0; unit_drop_cargo(&tg.gen, 0); tg.land.lnd_ship = -1; tg.land.lnd_land = -1; break; default: logerror("Bad trade type %d in trade\n", trade.trd_type); break; } unit_give_away(&tg.gen, trade.trd_maxbidder, 0); put_empobj(trade.trd_type, saveid, &tg.gen); nreport(seller, N_MAKE_SALE, trade.trd_maxbidder, 1); wu(0, seller, "%s bought %s #%d from you for $%.2f\n", cname(trade.trd_maxbidder), trade_nameof(&trade, &tg.gen), saveid, price * tradetax); wu(0, trade.trd_maxbidder, "The bidding is over & you bought %s #%d from %s for $%d\n", trade_nameof(&trade, &tg.gen), saveid, cname(seller), price); } return RET_OK; }
int enli(void) { struct nstr_sect nstr; struct sctstr sect; struct natstr *natp; int civ; int mil; int newmil; int milwant; int totalmil; int reserve; char *p; int quota; char prompt[128]; char buf[1024]; if (!snxtsct(&nstr, player->argp[1])) return RET_SYN; natp = getnatp(player->cnum); newmil = 500; sprintf(prompt, "Number to enlist (max %d) : ", newmil); if (!(p = getstarg(player->argp[2], prompt, buf))) return RET_SYN; if ((milwant = atoi(p)) > newmil) milwant = newmil; if (0 != (quota = (milwant < 0))) milwant = -milwant; totalmil = 0; reserve = natp->nat_reserve; if (reserve <= 0) { pr("No military reserves left\n"); return RET_OK; } while (nxtsct(&nstr, §)) { if (!player->owner) continue; if (sect.sct_oldown != player->cnum) continue; civ = sect.sct_item[I_CIVIL]; if (civ == 0) continue; if (sect.sct_loyal > 70) { pr("civilians refuse to report in %s!\n", xyas(sect.sct_x, sect.sct_y, player->cnum)); continue; } if (sect.sct_mobil <= 0) { pr("%s is out of mobility!\n", xyas(sect.sct_x, sect.sct_y, player->cnum)); } mil = sect.sct_item[I_MILIT]; newmil = civ * 0.5; if (quota) { if (newmil > milwant - mil) newmil = milwant - mil; if (newmil > 500) newmil = 500; } else if (newmil > milwant) newmil = milwant; if (newmil > 999 - mil) newmil = 999 - mil; if (newmil <= 0) continue; if (newmil > reserve) newmil = reserve; sect.sct_item[I_MILIT] = newmil + mil; reserve -= newmil; totalmil += newmil; sect.sct_item[I_CIVIL] = civ - newmil; pr("%3d enlisted in %s (%d)\n", newmil, xyas(sect.sct_x, sect.sct_y, player->cnum), mil + newmil); if (sect.sct_mobil > 0) sect.sct_mobil *= 1.0 - (double)newmil / (double)civ; putsect(§); if (totalmil >= 10000) { pr("Rioting in induction center interrupts enlistment\n"); break; } if (reserve == 0) { pr("Military reserve exhausted\n"); break; } } pr("Total new enlistment : %d\n", totalmil); pr("Military reserves stand at %d\n", reserve); if (totalmil) { natp->nat_reserve -= totalmil; putnat(natp); } if ((player->btused += roundavg(totalmil * 0.02)) > 0) pr("Paperwork at recruiting stations ... %d\n", player->btused); return RET_OK; }
int check_market(void) { struct comstr comm; struct sctstr *sect; struct natstr *natp; int m; int n; time_t now; double gain; double price; for (n = 0; getcomm(n, &comm); n++) { if (comm.com_maxbidder == comm.com_owner || comm.com_owner == 0) continue; (void)time(&now); if (comm.com_markettime + MARK_DELAY > now) continue; if (CANT_HAPPEN(comm.com_type <= I_NONE || comm.com_type > I_MAX)) continue; sect = getsectp(comm.com_x, comm.com_y); m = sect->sct_item[comm.com_type]; price = comm.com_price * comm.com_amount * buytax; gain = comm.com_price * comm.com_amount; natp = getnatp(comm.com_maxbidder); if (natp->nat_money < price) { nreport(comm.com_maxbidder, N_WELCH_DEAL, comm.com_owner, 1); wu(0, comm.com_maxbidder, "You didn't have enough cash to cover the cost.\n"); wu(0, comm.com_owner, "Sale #%d fell through. Goods remain on the market.\n", n); comm.com_maxbidder = comm.com_owner; } else if (sect->sct_type != SCT_WAREH && sect->sct_type != SCT_HARBR) { wu(0, comm.com_maxbidder, "Sector not a warehouse now, sale #%d fell though.\n", n); wu(0, comm.com_owner, "Sale #%d fell through. Goods remain on the market.\n", n); comm.com_maxbidder = comm.com_owner; } else if (m + comm.com_amount > ITEM_MAX) { wu(0, comm.com_maxbidder, "Warehouse full, sale #%d fell though.\n", n); wu(0, comm.com_owner, "Sale #%d fell through. Goods remain on the market.\n", n); comm.com_maxbidder = comm.com_owner; } else { sect->sct_item[comm.com_type] = m + comm.com_amount; putsect(sect); nreport(comm.com_owner, N_MAKE_SALE, comm.com_maxbidder, 1); wu(0, comm.com_owner, "%s bought %d %s from you for $%.2f\n", cname(comm.com_maxbidder), comm.com_amount, ichr[comm.com_type].i_name, gain); wu(0, comm.com_maxbidder, "You just bought %d %s from %s for $%.2f\n", comm.com_amount, ichr[comm.com_type].i_name, cname(comm.com_owner), price); natp->nat_money -= roundavg(price); putnat(natp); natp = getnatp(comm.com_owner); natp->nat_money += roundavg(gain); putnat(natp); comm.com_owner = 0; } comm.com_owner = 0; putcomm(n, &comm); } return RET_OK; }
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; }
int zdon(void) { int whichcnum; struct natstr *natp; char *p; int checking; int wantupd; int totpop; int totwant; int dowant; char buf[1024]; if (update_demand != UPD_DEMAND_SCHED && update_demand != UPD_DEMAND_ASYNC) { pr("Demand updates are not enabled.\n"); return RET_FAIL; } p = getstarg(player->argp[1], "Want update? [Yes|No|Check] ", buf); if (!p) return RET_SYN; if (*p == 'y' || *p == 'Y') { checking = 0; wantupd = 1; } else if (*p == 'n' || *p == 'N') { checking = 0; wantupd = 0; } else { checking = 1; wantupd = 0; } if (player->god) { whichcnum = natarg(player->argp[2], "for which country? "); if (whichcnum < 0) return RET_SYN; } else whichcnum = player->cnum; if (!(natp = getnatp(whichcnum))) { pr("Unable to find country. %d\n", whichcnum); pr("Notify the Deity.\n"); return RET_FAIL; } if (!checking) { if (wantupd) { if (influx(natp)) { pr("Unable to request an update as the country is in flux\n"); return RET_FAIL; } pr("You (%d) now want an update.\n", whichcnum); } else { pr("You (%d) now DON'T want an update.\n", whichcnum); } natp->nat_update = wantupd; putnat(natp); } dowant = demand_update_want(&totwant, &totpop, whichcnum); if (checking) { if (dowant) { pr("You want an update.\n"); } else pr("You DON'T want an update, yet.\n"); } pr("%d of a total of %d lunatics want an update.\n", totwant, totpop); if (!checking && wantupd && demandupdatecheck()) { pr("Here goes...\n"); update_trigger(); } return RET_OK; }