region *new_region(int x, int y, struct plane *pl, int uid) { region *r; pnormalize(&x, &y, pl); r = rfindhash(x, y); if (r) { log_error("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), x, y); if (r->units) log_error("duplicate region contains units\n"); return r; } r = calloc(1, sizeof(region)); r->x = x; r->y = y; r->uid = uid; r->age = 1; r->_plane = pl; rhash(r); hash_uid(r); if (last) addlist(&last, r); else addlist(®ions, r); last = r; assert(r->next == NULL); r->index = ++max_index; return r; }
static void smooth_island(region_list * island) { region *rn[MAXDIRECTIONS]; region_list *rlist = NULL; for (rlist = island; rlist; rlist = rlist->next) { region *r = rlist->data; int n, nland = 0; if (r->land) { get_neighbours(r, rn); for (n = 0; n != MAXDIRECTIONS && nland <= 1; ++n) { if (rn[n]->land) { ++nland; r = rn[n]; } } if (nland == 1) { get_neighbours(r, rn); oceans_around(r, rn); for (n = 0; n != MAXDIRECTIONS; ++n) { int n1 = (n + 1) % MAXDIRECTIONS; int n2 = (n + 1 + MAXDIRECTIONS) % MAXDIRECTIONS; if (!rn[n]->land && rn[n1] != r && rn[n2] != r) { r = rlist->data; runhash(r); runhash(rn[n]); SWAP_INTS(r->x, rn[n]->x); SWAP_INTS(r->y, rn[n]->y); rhash(r); rhash(rn[n]); rlist->data = r; oceans_around(r, rn); break; } } } } } }
/* * pass a route to the kernel or /ip. Don't bother if it is just the default * gateway. */ void installroute(Route *r) { int fd; uint32_t h; Route *hp; uint8_t net[Pasize]; /* * don't install routes whose gateway is 00000000 */ if(equivip(r->gate, ralloc.def.dest)) return; fd = open(routefile, ORDWR); if(fd < 0){ fprint(2, "can't open oproute\n"); return; } h = rhash(r->dest); /* * if the gateway is the same as the default gateway * we may be able to avoid a entry in the kernel */ if(equivip(r->gate, ralloc.def.gate)){ /* * look for a less specific match */ for(hp = ralloc.hash[h]; hp; hp = hp->next){ v4maskip(hp->mask, r->dest, net); if(equivip(net, hp->dest) && !equivip(hp->gate, ralloc.def.gate)) break; } /* * if no less specific match, just use the default */ if(hp == 0){ if(!readonly) fprint(fd, "delete %V", r->dest); if(debug) fprint(2, "delete %V\n", r->dest); close(fd); return; } } if(!readonly) fprint(fd, "add %V %V %V", r->dest, r->mask, r->gate); if(debug) fprint(2, "add %V & %V -> %V\n", r->dest, r->mask, r->gate); close(fd); }
/* * consider installing a route. Do so only if it is better than what * we have. */ void considerroute(Route *r) { uint32_t h; Route *hp; if(debug) fprint(2, "consider %16V & %16V -> %16V %d\n", r->dest, r->mask, r->gate, r->metric); r->next = 0; r->time = now; r->inuse = 1; /* don't allow our default route to be highjacked */ if(equivip(r->dest, ralloc.def.dest) || equivip(r->mask, ralloc.def.mask)) return; h = rhash(r->dest); for(hp = ralloc.hash[h]; hp; hp = hp->next){ if(equivip(hp->dest, r->dest)){ /* * found a match, replace if better (or much newer) */ if(r->metric < hp->metric || now-hp->time > 5*60){ removeroute(hp); memmove(hp->mask, r->mask, Pasize); memmove(hp->gate, r->gate, Pasize); hp->metric = r->metric; installroute(hp); } if(equivip(hp->gate, r->gate)) hp->time = now; return; } } /* * no match, look for space */ for(hp = ralloc.route; hp < &ralloc.route[Nroute]; hp++) if(hp->inuse == 0) break; if(hp == 0) fatal(0, "no more routes"); memmove(hp, r, sizeof(Route)); hp->next = ralloc.hash[h]; ralloc.hash[h] = hp; installroute(hp); }
static void move_iceberg(region * r) { attrib *a; direction_t dir; region *rc; a = a_find(r->attribs, &at_iceberg); if (!a) { dir = (direction_t) (rng_int() % MAXDIRECTIONS); a = a_add(&r->attribs, make_iceberg(dir)); } else { if (rng_int() % 100 < 20) { dir = (direction_t) (rng_int() % MAXDIRECTIONS); a->data.i = dir; } else { dir = (direction_t) a->data.i; } } rc = rconnect(r, dir); if (rc && !fval(rc->terrain, ARCTIC_REGION)) { if (fval(rc->terrain, SEA_REGION)) { /* Eisberg treibt */ ship *sh, *shn; unit *u; int x, y; for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); for (u = r->units; u; u = u->next) if (!fval(u->faction, FFL_SELECT)) { fset(u->faction, FFL_SELECT); ADDMSG(&u->faction->msgs, msg_message("iceberg_drift", "region dir", r, dir)); } x = r->x; y = r->y; runhash(r); runhash(rc); r->x = rc->x; r->y = rc->y; rc->x = x; rc->y = y; rhash(rc); rhash(r); /* rc ist der Ozean (Ex-Eisberg), r der Eisberg (Ex-Ozean) */ /* Schiffe aus dem Zielozean werden in den Eisberg transferiert * und nehmen Schaden. */ for (sh = r->ships; sh; sh = sh->next) freset(sh, SF_SELECT); for (sh = r->ships; sh; sh = sh->next) { /* Meldung an Kapitän */ float dmg = get_param_flt(global.parameters, "rules.ship.damage.intoiceberg", 0.10F); damage_ship(sh, dmg); fset(sh, SF_SELECT); } /* Personen, Schiffe und Gebäude verschieben */ while (rc->buildings) { rc->buildings->region = r; translist(&rc->buildings, &r->buildings, rc->buildings); } while (rc->ships) { float dmg = get_param_flt(global.parameters, "rules.ship.damage.withiceberg", 0.10F); fset(rc->ships, SF_SELECT); damage_ship(rc->ships, dmg); move_ship(rc->ships, rc, r, NULL); } while (rc->units) { building *b = rc->units->building; u = rc->units; u->building = 0; /* prevent leaving in move_unit */ move_unit(rc->units, r, NULL); u_set_building(u, b); /* undo leave-prevention */ } /* Beschädigte Schiffe können sinken */ for (sh = r->ships; sh;) { shn = sh->next; if (fval(sh, SF_SELECT)) { u = ship_owner(sh); if (sh->damage >= sh->size * DAMAGE_SCALE) { if (u != NULL) { ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", "ship", sh)); } remove_ship(&sh->region->ships, sh); } else if (u != NULL) { ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg", "ship", sh)); } } sh = shn; } } else if (rng_int() % 100 < 20) { /* Eisberg bleibt als Gletscher liegen */ unit *u; rsetterrain(r, T_GLACIER); a_remove(&r->attribs, a); for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); for (u = r->units; u; u = u->next) if (!fval(u->faction, FFL_SELECT)) { fset(u->faction, FFL_SELECT); ADDMSG(&u->faction->msgs, msg_message("iceberg_land", "region", r)); } } } }