/** ** GM: SKILL <unit> <skill> <tage> ** requires: permission-key "gmskil" **/ static void gm_skill(const void *tnext, struct unit *u, struct order *ord) { unit *to = findunit(getid()); skill_t skill = findskill(getstrtoken(), u->faction->locale); int num = getint(); if (to == NULL || rplane(to->region) != rplane(u->region)) { /* unknown or in another plane */ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); } else if (skill == NOSKILL || skill == SK_MAGIC || skill == SK_ALCHEMY) { /* unknown or not enough */ mistake(u, ord, "unknown skill, or skill cannot be raised."); } else if (num < 0 || num > 30) { /* sanity check failed */ mistake(u, ord, "invalid value."); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmskil"))) { mistake(u, ord, "permission denied."); } else { set_level(to, skill, num); } } }
/** ** GM: TELL <unit> <string> ** requires: permission-key "gmmsgr" **/ static void gm_messageunit(const void *tnext, struct unit *u, struct order *ord) { const struct plane *p = rplane(u->region); unit *target = findunit(getid()); const char *msg = getstrtoken(); region *r; if (target == NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); return; } r = target->region; if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmmsgu"))) { mistake(u, ord, "permission denied."); } else { add_message(&target->faction->msgs, msg_message("regionmessage", "region sender string", r, u, msg)); } } }
/** ** GM: TAKE <unit> <int> <itemtype> ** requires: permission-key "gmtake" **/ static void gm_take(const void *tnext, struct unit *u, struct order *ord) { unit *to = findunit(getid()); int num = getint(); const item_type *itype = finditemtype(getstrtoken(), u->faction->locale); if (to == NULL || rplane(to->region) != rplane(u->region)) { /* unknown or in another plane */ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); } else if (itype == NULL || i_get(to->items, itype) == 0) { /* unknown or not enough */ mistake(u, ord, "invalid item or item not found."); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmtake"))) { mistake(u, ord, "permission denied."); } else { int i = i_get(to->items, itype); if (i < num) num = i; if (num) { i_change(&to->items, itype, -num); i_change(&u->items, itype, num); } } } }
static void gm_messagefaction(const void *tnext, struct unit *gm, struct order *ord) { int n = getid(); faction *f = findfaction(n); const char *msg = getstrtoken(); plane *p = rplane(gm->region); attrib *permissions = a_find(gm->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { mistake(gm, ord, "permission denied."); return; } if (f != NULL) { region *r; for (r = regions; r; r = r->next) if (rplane(r) == p) { unit *u; for (u = r->units; u; u = u->next) if (u->faction == f) { add_message(&f->msgs, msg_message("msg_event", "string", msg)); return; } } } mistake(gm, ord, "cannot send messages to this faction."); }
/** ** GM: KILL FACTION <id> <string> ** requires: permission-key "gmmsgr" **/ static void gm_killfaction(const void *tnext, struct unit *u, struct order *ord) { int n = getid(); faction *f = findfaction(n); const char *msg = getstrtoken(); plane *p = rplane(u->region); attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { mistake(u, ord, "permission denied."); return; } if (f != NULL) { region *r; for (r = regions; r; r = r->next) if (rplane(r) == p) { unit *target; for (target = r->units; target; target = target->next) { if (target->faction == f) { scale_number(target, 0); ADDMSG(&target->faction->msgs, msg_message("killedbygm", "region unit string", r, target, msg)); return; } } } } mistake(u, ord, "cannot remove a unit from this faction."); }
/** ** GM: TELL PLANE <string> ** requires: permission-key "gmmsgr" **/ static void gm_messageplane(const void *tnext, struct unit *gm, struct order *ord) { const struct plane *p = rplane(gm->region); const char *zmsg = getstrtoken(); if (p == NULL) { mistake(gm, ord, "In diese Ebene kann keine Nachricht gesandt werden."); } else { /* checking permissions */ attrib *permissions = a_find(gm->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { mistake(gm, ord, "permission denied."); } else { message *msg = msg_message("msg_event", "string", zmsg); faction *f; region *r; for (f = factions; f; f = f->next) { freset(f, FFL_SELECT); } for (r = regions; r; r = r->next) { unit *u; if (rplane(r) != p) continue; for (u = r->units; u; u = u->next) if (!fval(u->faction, FFL_SELECT)) { f = u->faction; fset(f, FFL_SELECT); add_message(&f->msgs, msg); } } msg_release(msg); } } }
/** ** GM: TELEPORT <unit> <x> <y> ** requires: permission-key "gmtele" **/ static void gm_teleport(const void *tnext, struct unit *u, struct order *ord) { const struct plane *p = rplane(u->region); unit *to = findunit(getid()); int x = rel_to_abs(p, u->faction, getint(), 0); int y = rel_to_abs(p, u->faction, getint(), 1); region *r = findregion(x, y); if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else if (to == NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); } else if (rplane(to->region) != rplane(r) && !ucontact(to, u)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", to)); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmtele"))) { mistake(u, ord, "permission denied."); } else move_unit(to, r, NULL); } }
/** ** GM: TERRAFORM <x> <y> <terrain> ** requires: permission-key "gmterf" **/ static void gm_terraform(const void *tnext, struct unit *u, struct order *ord) { const struct plane *p = rplane(u->region); int x = rel_to_abs(p, u->faction, getint(), 0); int y = rel_to_abs(p, u->faction, getint(), 1); const char *c = getstrtoken(); variant token; void **tokens = get_translations(u->faction->locale, UT_TERRAINS); region *r; pnormalize(&x, &y, p); r = findregion(x, y); if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); return; } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmterf"))) return; } if (findtoken(*tokens, c, &token) != E_TOK_NOMATCH) { const terrain_type *terrain = (const terrain_type *)token.v; terraform_region(r, terrain); } }
/** ** GM: GATE <id> <x> <y> ** requires: permission-key "gmgate" **/ static void gm_gate(const void *tnext, struct unit * u, struct order *ord) { const struct plane *pl = rplane(u->region); int id = getid(); int x = rel_to_abs(pl, u->faction, getint(), 0); int y = rel_to_abs(pl, u->faction, getint(), 1); building *b = findbuilding(id); region *r; pnormalize(&x, &y, pl); r = findregion(x, y); if (b == NULL || r == NULL || pl != rplane(b->region) || pl != rplane(r)) { mistake(u, ord, "the unit cannot transform this building."); return; } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (permissions && has_permission(permissions, atoi36("gmgate"))) { remove_triggers(&b->attribs, "timer", &tt_gate); remove_triggers(&b->attribs, "create", &tt_unguard); if (r != b->region) { add_trigger(&b->attribs, "timer", trigger_gate(b, r)); add_trigger(&b->attribs, "create", trigger_unguard(b)); fset(b, BLD_UNGUARDED); } } } }
static int use_speedsail(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { struct plane *p = rplane(u->region); unused_arg(amount); unused_arg(itype); if (p != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); } else { if (u->ship) { attrib *a = a_find(u->ship->attribs, &at_speedup); if (a == NULL) { a = a_add(&u->ship->attribs, a_new(&at_speedup)); a->data.sa[0] = 50; /* speed */ a->data.sa[1] = 50; /* decay */ ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit", u)); /* Ticket abziehen */ i_change(&u->items, itype, -1); return 0; } else { cmistake(u, ord, 211, MSG_EVENT); } } else { cmistake(u, ord, 144, MSG_EVENT); } } return EUNUSABLE; }
int get_modifier(const unit * u, skill_t sk, int level, const region * r, bool noitem) { int bskill = level; int skill = bskill; if (r && sk == SK_STEALTH) { plane *pl = rplane(r); if (pl && fval(pl, PFL_NOSTEALTH)) { return 0; } } skill += rc_skillmod(u_race(u), r, sk); skill += att_modification(u, sk); if (!noitem) { skill = item_modification(u, sk, skill); } skill = skillmod(u->attribs, u, r, sk, skill, SMF_ALWAYS); #ifdef HUNGER_REDUCES_SKILL if (fval(u, UFL_HUNGER)) { skill = skill / 2; } #endif return skill - bskill; }
static void frame_regions(int age, const terrain_type * terrain) { plane *hplane = get_homeplane(); region *r = regions; for (r = regions; r; r = r->next) { plane *pl = rplane(r); direction_t d; if (r->age < age) continue; if (pl != hplane) continue; /* only do this on the main world */ if (r->terrain == terrain) continue; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn == NULL) { int x = r->x + delta_x[d]; int y = r->y + delta_y[d]; pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, terrain); rn->age = r->age; } } } }
static int tolua_faction_set_origin(lua_State * L) { faction *f = (faction *)tolua_tousertype(L, 1, 0); region *r = (region *)tolua_tousertype(L, 2, 0); plane *pl = rplane(r); int id = pl ? pl->id : 0; set_ursprung(f, id, r->x - plane_center_x(pl), r->y - plane_center_y(pl)); return 0; }
/** ** GM: TELL REGION <x> <y> <string> ** requires: permission-key "gmmsgr" **/ static void gm_messageregion(const void *tnext, struct unit *u, struct order *ord) { const struct plane *p = rplane(u->region); int x = rel_to_abs(p, u->faction, getint(), 0); int y = rel_to_abs(p, u->faction, getint(), 1); const char *msg = getstrtoken(); region *r = findregion(x, y); if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { mistake(u, ord, "permission denied."); } else { add_message(&r->msgs, msg_message("msg_event", "string", msg)); } } }
/** ** GM: KILL UNIT <id> <string> ** requires: permission-key "gmkill" **/ static void gm_killunit(const void *tnext, struct unit *u, struct order *ord) { const struct plane *p = rplane(u->region); unit *target = findunit(getid()); const char *msg = getstrtoken(); region *r = target->region; if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { mistake(u, ord, "permission denied."); } else { scale_number(target, 0); ADDMSG(&target->faction->msgs, msg_message("killedbygm", "region unit string", r, target, msg)); } } }
static int summon_igjarjuk(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { struct plane *p = rplane(u->region); unused_arg(amount); unused_arg(itype); if (p != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); return EUNUSABLE; } else { assert(!"not implemented"); return EUNUSABLE; } }
static int tolua_faction_normalize(lua_State * L) { faction *f = (faction *)tolua_tousertype(L, 1, 0); region *r = (region *)tolua_tousertype(L, 2, 0); if (r) { plane *pl = rplane(r); int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); tolua_pushnumber(L, (lua_Number)nx); tolua_pushnumber(L, (lua_Number)ny); return 2; } return 0; }
static void oceans_around(region * r, region * rn[]) { int n; for (n = 0; n != MAXDIRECTIONS; ++n) { region *rx = rn[n]; if (rx == NULL) { plane *pl = rplane(r); int x = r->x + delta_x[n]; int y = r->y + delta_y[n]; pnormalize(&x, &y, pl); rx = new_region(x, y, pl, 0); terraform_region(rx, newterrain(T_OCEAN)); rn[n] = rx; } } }
const char *write_regionname(const region * r, const faction * f, char *buffer, size_t size) { char *buf = (char *)buffer; const struct locale *lang = f ? f->locale : 0; if (r == NULL) { strlcpy(buf, "(null)", size); } else { plane *pl = rplane(r); int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); slprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); } return buffer; }
static int use_museumticket(unit * u, const struct item_type *itype, int amount, order * ord) { attrib *a; region *r = u->region; plane *pl = rplane(r); unused_arg(amount); /* Pruefen ob in normaler Plane und nur eine Person */ if (pl != get_homeplane()) { cmistake(u, ord, 265, MSG_MAGIC); return 0; } if (u->number != 1) { cmistake(u, ord, 267, MSG_MAGIC); return 0; } if (has_horses(u)) { cmistake(u, ord, 272, MSG_MAGIC); return 0; } /* In diesem Attribut merken wir uns, wohin die Einheit zurückgesetzt * wird, wenn sie das Museum verläßt. */ a = a_add(&u->attribs, a_new(&at_museumexit)); a->data.sa[0] = (short)r->x; a->data.sa[1] = (short)r->y; /* Benutzer in die Halle teleportieren */ move_unit(u, findregion(9525, 9525), NULL); /* Ticket abziehen */ i_change(&u->items, itype, -1); /* Benutzer ein Exitticket geben */ i_change(&u->items, itype, 1); return 0; }
int lifestyle(const unit * u) { int need; plane *pl; static int gamecookie = -1; if (gamecookie != global.cookie) { gamecookie = global.cookie; } if (is_monsters(u->faction)) return 0; need = maintenance_cost(u); pl = rplane(u->region); if (pl && fval(pl, PFL_NOFEED)) return 0; return need; }
/* update_lighthouse: call this function whenever the size of a lighthouse changes * it adds temporary markers to the surrounding regions. * The existence of markers says nothing about the quality of the observer in * the lighthouse, for this may change more frequently. */ void update_lighthouse(building * lh) { if (is_building_type(lh->type, "lighthouse")) { region *r = lh->region; r->flags |= RF_LIGHTHOUSE; if (lh->size > 0) { int d = (int)log10(lh->size) + 1; int x; for (x = -d; x <= d; ++x) { int y; for (y = -d; y <= d; ++y) { attrib *a; region *r2; int px = r->x + x, py = r->y + y; pnormalize(&px, &py, rplane(r)); r2 = findregion(px, py); if (!r2 || !fval(r2->terrain, SEA_REGION)) continue; if (distance(r, r2) > d) continue; a = a_find(r2->attribs, &at_lighthouse); while (a && a->type == &at_lighthouse) { building *b = (building *)a->data.v; if (b == lh) break; a = a->next; } if (!a) { a = a_add(&r2->attribs, a_new(&at_lighthouse)); a->data.v = (void *)lh; } } } } } }
region *r_connect(const region * r, direction_t dir) { region *result; int x, y; #ifdef FAST_CONNECT region *rmodify = (region *)r; assert(dir >= 0 && dir < MAXDIRECTIONS); if (r->connect[dir]) return r->connect[dir]; #endif assert(dir < MAXDIRECTIONS); x = r->x + delta_x[dir]; y = r->y + delta_y[dir]; pnormalize(&x, &y, rplane(r)); result = rfindhash(x, y); #ifdef FAST_CONNECT if (result) { rmodify->connect[dir] = result; result->connect[back[dir]] = rmodify; } #endif return result; }
int random_neighbours(region * r, region_list ** rlist, const terrain_type * (*terraformer) (direction_t)) { int nsize = 0; direction_t dir; for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *rn = rconnect(r, dir); if (rn == NULL) { const terrain_type *terrain = terraformer(dir); plane *pl = rplane(r); int x = r->x + delta_x[dir]; int y = r->y + delta_y[dir]; pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, terrain); regionqueue_push(rlist, rn); if (rn->land) { ++nsize; } } } return nsize; }
/** create new island with up to nsize players * returns the number of players placed on the new island. */ int autoseed(newfaction ** players, int nsize, int max_agediff) { region *r = NULL; region_list *rlist = NULL; int rsize = 0, tsize = 0; int isize = REGIONS_PER_FACTION; /* target size for the island */ int psize = 0; /* players on this island */ const terrain_type *volcano_terrain = get_terrain("volcano"); static int nterrains = -1; static const terrain_type **terrainarr = 0; static int *distribution; assert(players); if (nterrains < 0) { int n = 0; const terrain_type *terrain = terrains(); for (nterrains = 0; terrain; terrain = terrain->next) { if (terrain->distribution) { ++nterrains; } } terrainarr = malloc(sizeof(terrain_type *) * nterrains); distribution = malloc(sizeof(int) * nterrains); for (terrain = terrains(); terrain; terrain = terrain->next) { if (terrain->distribution) { terrainarr[n] = terrain; distribution[n++] = terrain->distribution; } } } frame_regions(16, newterrain(T_FIREWALL)); if (listlen(*players) < MINFACTIONS) return 0; if (max_agediff > 0) { region *rmin = NULL; plane *hplane = get_homeplane(); /* find a spot that's adjacent to the previous island, but virgin. * like the last land virgin ocean region adjacent to land. */ for (r = regions; r; r = r->next) { struct plane *pl = rplane(r); if (r->age <= max_agediff && r->terrain == newterrain(T_OCEAN) && pl == hplane && virgin_region(r)) { direction_t d; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn && rn->land && rn->age <= max_agediff && virgin_region(rn)) { /* only expand islands that aren't single-islands and not too big already */ int size, inhabitants, maxage; get_island_info(rn, &size, &inhabitants, &maxage); if (maxage <= max_agediff && size >= 2 && size < MAXISLANDSIZE) { rmin = rn; break; } } } } } if (rmin != NULL) { faction *f; quicklist *ql, *rlist = get_island(rmin); int qi; for (ql = rlist, qi = 0; ql; ql_advance(&ql, &qi, 1)) { region *r = (region *)ql_get(ql, qi); unit *u; for (u = r->units; u; u = u->next) { f = u->faction; if (!fval(f, FFL_MARK)) { ++psize; fset(f, FFL_MARK); } } } ql_free(rlist); if (psize > 0) { for (f = factions; f; f = f->next) { freset(f, FFL_MARK); } } if (psize < PLAYERS_PER_ISLAND) { r = rmin; } } } if (r == NULL) { region *rmin = NULL; direction_t dmin = MAXDIRECTIONS; plane *hplane = get_homeplane(); /* find an empty spot. * rmin = the youngest ocean region that has a missing neighbour * dmin = direction in which it's empty */ for (r = regions; r; r = r->next) { struct plane *pl = rplane(r); if (r->terrain == newterrain(T_OCEAN) && pl == hplane && (rmin == NULL || r->age <= max_agediff)) { direction_t d; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn == NULL) break; } if (d != MAXDIRECTIONS) { rmin = r; dmin = d; } } } /* create a new region where we found the empty spot, and make it the first * in our island. island regions are kept in rlist, so only new regions can * get populated, and old regions are not overwritten */ if (rmin != NULL) { plane *pl = rplane(rmin); int x = rmin->x + delta_x[dmin]; int y = rmin->y + delta_y[dmin]; pnormalize(&x, &y, pl); assert(virgin_region(rconnect(rmin, dmin))); r = new_region(x, y, pl, 0); terraform_region(r, newterrain(T_OCEAN)); } } if (r != NULL) { add_regionlist(&rlist, r); fset(r, RF_MARK); rsize = 1; } while (rsize && (nsize || isize >= REGIONS_PER_FACTION)) { int i = rng_int() % rsize; region_list **rnext = &rlist; region_list *rfind; direction_t d; while (i--) rnext = &(*rnext)->next; rfind = *rnext; r = rfind->data; freset(r, RF_MARK); *rnext = rfind->next; free(rfind); --rsize; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn && fval(rn, RF_MARK)) continue; if (rn == NULL) { plane *pl = rplane(r); int x = r->x + delta_x[d]; int y = r->y + delta_y[d]; pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, newterrain(T_OCEAN)); } if (virgin_region(rn)) { add_regionlist(&rlist, rn); fset(rn, RF_MARK); ++rsize; } } if (volcano_terrain != NULL && (rng_int() % VOLCANO_CHANCE == 0)) { terraform_region(r, volcano_terrain); } else if (nsize && (rng_int() % isize == 0 || rsize == 0)) { newfaction **nfp, *nextf = *players; faction *f; unit *u; isize += REGIONS_PER_FACTION; terraform_region(r, preferred_terrain(nextf->race)); prepare_starting_region(r); ++tsize; assert(r->land && r->units == 0); u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, nextf->lang, nextf->subscription)); f = u->faction; fset(f, FFL_ISNEW); f->alliance = nextf->allies; /* remove duplicate email addresses */ nfp = &nextf->next; while (*nfp) { newfaction *nf = *nfp; if (strcmp(nextf->email, nf->email) == 0) { *nfp = nf->next; free_newfaction(nf); } else nfp = &nf->next; } *players = nextf->next; free_newfaction(nextf); ++psize; --nsize; --isize; if (psize >= PLAYERS_PER_ISLAND) break; } else { terraform_region(r, random_terrain(terrainarr, distribution, nterrains)); --isize; } } if (nsize != 0) { log_error( ("Could not place all factions on the same island as requested\n")); } if (rlist) { #define MINOCEANDIST 3 #define MAXOCEANDIST 6 #define MAXFILLDIST 10 #define SPECIALCHANCE 80 region_list **rbegin = &rlist; int special = 1; int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST - MINOCEANDIST)); while (oceandist--) { region_list **rend = rbegin; while (*rend) rend = &(*rend)->next; while (rbegin != rend) { direction_t d; region *r = (*rbegin)->data; rbegin = &(*rbegin)->next; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn == NULL) { const struct terrain_type *terrain = newterrain(T_OCEAN); plane *pl = rplane(r); int x = r->x + delta_x[d]; int y = r->y + delta_y[d]; pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); if (rng_int() % SPECIALCHANCE < special) { terrain = random_terrain(terrainarr, distribution, nterrains); special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ } else { special = 1; } terraform_region(rn, terrain); /* the new region has an extra 20% chance to have mallorn */ if (rng_int() % 100 < 20) fset(r, RF_MALLORN); add_regionlist(rend, rn); } } } } while (*rbegin) { region *r = (*rbegin)->data; plane *pl = rplane(r); direction_t d; rbegin = &(*rbegin)->next; for (d = 0; d != MAXDIRECTIONS; ++d) if (rconnect(r, d) == NULL) { int i; for (i = 1; i != MAXFILLDIST; ++i) { int x = r->x + delta_x[d] * i; int y = r->y + delta_y[d] * i; pnormalize(&x, &y, pl); if (findregion(x, y)) { break; } } if (i != MAXFILLDIST) { while (--i) { region *rn; int x = r->x + delta_x[d] * i; int y = r->y + delta_y[d] * i; pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, newterrain(T_OCEAN)); } } } } while (rlist) { region_list *self = rlist; rlist = rlist->next; freset(self->data, RF_MARK); free(self); } } return tsize; }
void get_food(region * r) { plane *pl = rplane(r); unit *u; int peasantfood = rpeasants(r) * 10; static int food_rules = -1; static int gamecookie = -1; if (food_rules < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; food_rules = get_param_int(global.parameters, "rules.economy.food", 0); } if (food_rules & FOOD_IS_FREE) { return; } /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber * wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise * jede Einheit genug Silber für ihren Unterhalt hat. */ for (u = r->units; u; u = u->next) { int need = lifestyle(u); /* Erstmal zurücksetzen */ freset(u, UFL_HUNGER); if (u->ship && (u->ship->flags & SF_FISHING)) { unit *v; int c = 2; for (v = u; c > 0 && v; v = v->next) { if (v->ship == u->ship) { int get = 0; if (v->number <= c) { get = lifestyle(v); } else { get = lifestyle(v) * c / v->number; } if (get) { change_money(v, get); } } c -= v->number; } u->ship->flags -= SF_FISHING; } if (food_rules & FOOD_FROM_PEASANTS) { struct faction *owner = region_get_owner(r); /* if the region is owned, and the owner is nice, then we'll get * food from the peasants - should not be used with WORK */ if (owner != NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { int rm = rmoney(r); int use = _min(rm, need); rsetmoney(r, rm - use); need -= use; } } need -= get_money(u); if (need > 0) { unit *v; for (v = r->units; need && v; v = v->next) { if (v->faction == u->faction && help_money(v)) { int give = get_money(v) - lifestyle(v); give = _min(need, give); if (give > 0) { change_money(v, -give); change_money(u, give); need -= give; } } } } } /* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird * entsprechend verteilt. */ for (u = r->units; u; u = u->next) { int need = lifestyle(u); faction *f = u->faction; need -= _max(0, get_money(u)); if (need > 0) { unit *v; if (food_rules & FOOD_FROM_OWNER) { /* the owner of the region is the first faction to help out when you're hungry */ faction *owner = region_get_owner(r); if (owner && owner != u->faction) { for (v = r->units; v; v = v->next) { if (v->faction == owner && alliedunit(v, f, HELP_MONEY) && help_money(v)) { help_feed(v, u, &need); break; } } } } for (v = r->units; need && v; v = v->next) { if (v->faction != f && alliedunit(v, f, HELP_MONEY) && help_money(v)) { help_feed(v, u, &need); } } /* Die Einheit hat nicht genug Geld zusammengekratzt und * nimmt Schaden: */ if (need > 0) { int lspp = lifestyle(u) / u->number; if (lspp > 0) { int number = (need + lspp - 1) / lspp; if (hunger(number, u)) fset(u, UFL_HUNGER); } } } } /* 3. bestimmen, wie viele Bauern gefressen werden. * bei fehlenden Bauern den Dämon hungern lassen */ for (u = r->units; u; u = u->next) { if (u_race(u) == get_race(RC_DAEMON)) { int hungry = u->number; /* use peasantblood before eating the peasants themselves */ const struct potion_type *pt_blood = 0; const resource_type *rt_blood = rt_find("peasantblood"); if (rt_blood) { pt_blood = rt_blood->ptype; } if (pt_blood) { /* always start with the unit itself, then the first known unit that may have some blood */ unit *donor = u; while (donor != NULL && hungry > 0) { int blut = get_effect(donor, pt_blood); blut = _min(blut, hungry); if (blut) { change_effect(donor, pt_blood, -blut); hungry -= blut; } if (donor == u) donor = r->units; while (donor != NULL) { if (u_race(donor) == get_race(RC_DAEMON) && donor != u) { if (get_effect(donor, pt_blood)) { /* if he's in our faction, drain him: */ if (donor->faction == u->faction) break; } } donor = donor->next; } } } /* remaining demons feed on peasants */ if (pl == NULL || !fval(pl, PFL_NOFEED)) { if (peasantfood >= hungry) { peasantfood -= hungry; hungry = 0; } else { hungry -= peasantfood; peasantfood = 0; } if (hungry > 0) { static int demon_hunger = -1; if (demon_hunger < 0) { demon_hunger = get_param_int(global.parameters, "hunger.demons", 0); } if (demon_hunger == 0) { /* demons who don't feed are hungry */ if (hunger(hungry, u)) fset(u, UFL_HUNGER); } else { /* no damage, but set the hungry-flag */ fset(u, UFL_HUNGER); } } } } } rsetpeasants(r, peasantfood / 10); /* 3. Von den überlebenden das Geld abziehen: */ for (u = r->units; u; u = u->next) { int need = _min(get_money(u), lifestyle(u)); change_money(u, -need); } }
int teach_cmd(unit * teacher, struct order *ord) { plane *pl; region *r = teacher->region; skill_t sk_academy = NOSKILL; int teaching, i, j, count, academy_students = 0; if (r->attribs) { if (get_curse(r->attribs, &ct_gbdream)) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "gbdream_noteach", "")); return 0; } } if ((u_race(teacher)->flags & RCF_NOTEACH) || fval(teacher, UFL_WERE)) { cmistake(teacher, ord, 274, MSG_EVENT); return 0; } pl = rplane(r); if (pl && fval(pl, PFL_NOTEACH)) { cmistake(teacher, ord, 273, MSG_EVENT); return 0; } teaching = teacher->number * TEACHNUMBER; if ((i = get_effect(teacher, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ if (i > teaching) i = teaching; /* Trank wirkt pro Schueler, nicht pro Lehrer */ teaching -= i; change_effect(teacher, oldpotiontype[P_FOOL], -i); j = teaching; ADDMSG(&teacher->faction->msgs, msg_message("teachdumb", "teacher amount", teacher, j)); } if (teaching <= 0) return 0; count = 0; init_order_depr(ord); #if TEACH_ALL if (getparam(teacher->faction->locale) == P_ANY) { skill_t sk; unit *scholar; skill_t teachskill[MAXSKILLS]; int t = 0; do { sk = getskill(teacher->faction->locale); teachskill[t] = getskill(teacher->faction->locale); } while (sk != NOSKILL); for (scholar = r->units; teaching > 0 && scholar; scholar = scholar->next) { if (LongHunger(scholar)) { continue; } else if (scholar->faction == teacher->faction) { if (getkeyword(scholar->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_order(scholar->thisorder, scholar->faction->locale); sk = getskill(scholar->faction->locale); if (sk != NOSKILL && teachskill[0] != NOSKILL) { for (t = 0; teachskill[t] != NOSKILL; ++t) { if (sk == teachskill[t]) { break; } } sk = teachskill[t]; } if (sk != NOSKILL && effskill_study(teacher, sk) - TEACHDIFFERENCE > effskill_study(scholar, sk)) { teaching -= teach_unit(teacher, scholar, teaching, sk, true, &academy_students); } } } #ifdef TEACH_FRIENDS else if (alliedunit(teacher, scholar->faction, HELP_GUARD)) { if (getkeyword(scholar->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_order(scholar->thisorder, scholar->faction->locale); sk = getskill(scholar->faction->locale); if (sk != NOSKILL && effskill_study(teacher, sk) - TEACHDIFFERENCE >= effskill(scholar, sk, NULL)) { teaching -= teach_unit(teacher, scholar, teaching, sk, true, &academy_students); } } } #endif } } else #endif { char zOrder[4096]; size_t sz = sizeof(zOrder); order *new_order; zOrder[0] = '\0'; init_order_depr(ord); while (!parser_end()) { skill_t sk; unit *scholar; bool feedback; getunit(r, teacher->faction, &scholar); ++count; /* Falls die Unit nicht gefunden wird, Fehler melden */ if (!scholar) { char tbuf[20]; const char *uid; const char *token; /* Finde den string, der den Fehler verursacht hat */ parser_pushstate(); init_order_depr(ord); for (j = 0; j != count - 1; ++j) { /* skip over the first 'count' units */ getunit(r, teacher->faction, NULL); } token = getstrtoken(); /* Beginne die Fehlermeldung */ if (isparam(token, teacher->faction->locale, P_TEMP)) { token = getstrtoken(); sprintf(tbuf, "%s %s", LOC(teacher->faction->locale, parameters[P_TEMP]), token); uid = tbuf; } else { uid = token; } ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "unitnotfound_id", "id", uid)); parser_popstate(); continue; } feedback = teacher->faction == scholar->faction || alliedunit(scholar, teacher->faction, HELP_GUARD); /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in * ihre neuen Nummern uebersetzt. */ if (zOrder[0]) { strncat(zOrder, " ", sz - 1); --sz; } sz -= str_strlcpy(zOrder + 4096 - sz, itoa36(scholar->no), sz); if (getkeyword(scholar->thisorder) != K_STUDY) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_nolearn", "student", scholar)); continue; } /* Input ist nun von student->thisorder !! */ parser_pushstate(); init_order(scholar->thisorder, scholar->faction->locale); sk = getskill(scholar->faction->locale); parser_popstate(); if (sk == NOSKILL) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_nolearn", "student", scholar)); continue; } if (effskill_study(scholar, sk) > effskill_study(teacher, sk) - TEACHDIFFERENCE) { if (feedback) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_asgood", "student", scholar)); } continue; } if (sk == SK_MAGIC) { /* ist der Magier schon spezialisiert, so versteht er nur noch * Lehrer seines Gebietes */ magic_t mage2 = unit_get_magic(scholar); if (mage2 != M_GRAY) { magic_t mage1 = unit_get_magic(teacher); if (mage1 != mage2) { if (feedback) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "error_different_magic", "target", scholar)); } continue; } } } sk_academy = sk; teaching -= teach_unit(teacher, scholar, teaching, sk, false, &academy_students); } new_order = create_order(K_TEACH, teacher->faction->locale, "%s", zOrder); replace_order(&teacher->orders, ord, new_order); free_order(new_order); /* parse_order & set_order have each increased the refcount */ } if (academy_students > 0 && sk_academy!=NOSKILL) { academy_teaching_bonus(teacher, sk_academy, academy_students); } init_order_depr(NULL); return 0; }
static bool good_region(const region * r) { return (!fval(r, RF_CHAOTIC) && r->age > 30 && rplane(r) == NULL && r->units != NULL && r->land != NULL); }
static int tolua_region_get_plane(lua_State * L) { region *r = (region *)tolua_tousertype(L, 1, 0); tolua_pushusertype(L, rplane(r), TOLUA_CAST "plane"); return 1; }
int teach_cmd(unit * u, struct order *ord) { static const curse_type *gbdream_ct = NULL; plane *pl; region *r = u->region; int teaching, i, j, count, academy = 0; skill_t sk = NOSKILL; if (gbdream_ct == 0) gbdream_ct = ct_find("gbdream"); if (gbdream_ct) { if (get_curse(u->region->attribs, gbdream_ct)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "gbdream_noteach", "")); return 0; } } if ((u_race(u)->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { cmistake(u, ord, 274, MSG_EVENT); return 0; } pl = rplane(r); if (pl && fval(pl, PFL_NOTEACH)) { cmistake(u, ord, 273, MSG_EVENT); return 0; } teaching = u->number * 30 * TEACHNUMBER; if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ i = _min(i, u->number * TEACHNUMBER); /* Trank wirkt pro Schueler, nicht pro Lehrer */ teaching -= i * 30; change_effect(u, oldpotiontype[P_FOOL], -i); j = teaching / 30; ADDMSG(&u->faction->msgs, msg_message("teachdumb", "teacher amount", u, j)); } if (teaching == 0) return 0; count = 0; init_order(ord); #if TEACH_ALL if (getparam(u->faction->locale) == P_ANY) { unit *student = r->units; skill_t teachskill[MAXSKILLS]; int i = 0; do { sk = getskill(u->faction->locale); teachskill[i++] = sk; } while (sk != NOSKILL); while (teaching && student) { if (student->faction == u->faction) { if (LongHunger(student)) continue; if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_order(student->thisorder); sk = getskill(student->faction->locale); if (sk != NOSKILL && teachskill[0] != NOSKILL) { for (i = 0; teachskill[i] != NOSKILL; ++i) if (sk == teachskill[i]) break; sk = teachskill[i]; } if (sk != NOSKILL && eff_skill_study(u, sk, r) - TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { teaching -= teach_unit(u, student, teaching, sk, true, &academy); } } } student = student->next; } #ifdef TEACH_FRIENDS while (teaching && student) { if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) { if (LongHunger(student)) continue; if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_order(student->thisorder); sk = getskill(student->faction->locale); if (sk != NOSKILL && eff_skill_study(u, sk, r) - TEACHDIFFERENCE >= eff_skill(student, sk, r)) { teaching -= teach_unit(u, student, teaching, sk, true, &academy); } } } student = student->next; } #endif } else #endif { char zOrder[4096]; order *new_order; zOrder[0] = '\0'; init_order(ord); while (!parser_end()) { unit *u2; bool feedback; getunit(r, u->faction, &u2); ++count; /* Falls die Unit nicht gefunden wird, Fehler melden */ if (!u2) { char tbuf[20]; const char *uid; const char *token; /* Finde den string, der den Fehler verursacht hat */ parser_pushstate(); init_order(ord); for (j = 0; j != count - 1; ++j) { /* skip over the first 'count' units */ getunit(r, u->faction, NULL); } token = getstrtoken(); /* Beginne die Fehlermeldung */ if (isparam(token, u->faction->locale, P_TEMP)) { token = getstrtoken(); sprintf(tbuf, "%s %s", LOC(u->faction->locale, parameters[P_TEMP]), token); uid = tbuf; } else { uid = token; } ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id", "id", uid)); parser_popstate(); continue; } feedback = u->faction == u2->faction || alliedunit(u2, u->faction, HELP_GUARD); /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in * ihre neuen Nummern uebersetzt. */ if (zOrder[0]) strcat(zOrder, " "); strcat(zOrder, unitid(u2)); if (getkeyword(u2->thisorder) != K_STUDY) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_nolearn", "student", u2)); continue; } /* Input ist nun von u2->thisorder !! */ parser_pushstate(); init_order(u2->thisorder); sk = getskill(u2->faction->locale); parser_popstate(); if (sk == NOSKILL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_nolearn", "student", u2)); continue; } /* u is teacher, u2 is student */ if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r) - TEACHDIFFERENCE) { if (feedback) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_asgood", "student", u2)); } continue; } if (sk == SK_MAGIC) { /* ist der Magier schon spezialisiert, so versteht er nur noch * Lehrer seines Gebietes */ sc_mage *mage1 = get_mage(u); sc_mage *mage2 = get_mage(u2); if (!mage2 || !mage1 || (mage2->magietyp != M_GRAY && mage1->magietyp != mage2->magietyp)) { if (feedback) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_different_magic", "target", u2)); } continue; } } teaching -= teach_unit(u, u2, teaching, sk, false, &academy); } new_order = create_order(K_TEACH, u->faction->locale, "%s", zOrder); replace_order(&u->orders, ord, new_order); free_order(new_order); /* parse_order & set_order have each increased the refcount */ } if (academy && sk != NOSKILL) { academy = academy / 30; /* anzahl gelehrter wochen, max. 10 */ learn_skill(u, sk, academy / 30.0 / TEACHNUMBER); } return 0; }