Exemple #1
0
static void test_shipowner_goes_to_other_when_empty(CuTest * tc)
{
    struct region *r;
    struct ship *sh;
    struct unit *u, *u2;
    struct faction *f;
    const struct ship_type *stype;
    const struct race *human;

    test_setup();
    test_create_world();

    human = rc_find("human");
    CuAssertPtrNotNull(tc, human);

    stype = st_find("boat");
    CuAssertPtrNotNull(tc, stype);

    f = test_create_faction(human);
    r = findregion(0, 0);

    sh = test_create_ship(r, stype);
    CuAssertPtrNotNull(tc, sh);

    u2 = test_create_unit(f, r);
    u = test_create_unit(f, r);
    CuAssertPtrNotNull(tc, u);
    u_set_ship(u, sh);
    u_set_ship(u2, sh);
    CuAssertPtrEquals(tc, u, ship_owner(sh));
    u->number = 0;
    CuAssertPtrEquals(tc, u2, ship_owner(sh));
    test_teardown();
}
Exemple #2
0
static void test_ship_set_owner(CuTest * tc)
{
    struct region *r;
    struct ship *sh;
    struct unit *u1, *u2;
    struct faction *f;
    const struct ship_type *stype;
    const struct race *human;

    test_setup();
    test_create_world();

    human = rc_find("human");
    stype = st_find("boat");
    f = test_create_faction(human);
    r = findregion(0, 0);

    sh = test_create_ship(r, stype);
    u1 = test_create_unit(f, r);
    u_set_ship(u1, sh);
    CuAssertPtrEquals(tc, u1, ship_owner(sh));

    u2 = test_create_unit(f, r);
    u_set_ship(u2, sh);
    CuAssertPtrEquals(tc, u1, ship_owner(sh));
    ship_set_owner(u2);
    CuAssertPtrEquals(tc, u2, ship_owner(sh));
    test_teardown();
}
Exemple #3
0
static void test_shipspeed(CuTest *tc) {
    ship *sh;
    const ship_type *stype;
    unit *cap, *crew;

    test_setup();
    sh = setup_ship();
    stype = sh->type;

    CuAssertIntEquals_Msg(tc, "ship without a captain cannot move", 0, shipspeed(sh, NULL));

    setup_crew(sh, 0, &cap, &crew);

    CuAssertPtrEquals(tc, cap, ship_owner(sh));
    CuAssertIntEquals_Msg(tc, "ship with fully skilled crew can sail at max speed", 2, shipspeed(sh, cap));
    CuAssertIntEquals_Msg(tc, "shipspeed without a hint defaults to captain", 2, shipspeed(sh, NULL));

    set_level(cap, SK_SAILING, stype->cptskill + 5);
    set_level(crew, SK_SAILING, (stype->sumskill - stype->cptskill) * 10);
    CuAssertIntEquals_Msg(tc, "higher skills should not affect top speed", 2, shipspeed(sh, cap));
    set_level(cap, SK_SAILING, stype->cptskill);
    set_level(crew, SK_SAILING, stype->sumskill - stype->cptskill);

    CuAssertIntEquals(tc, 2, shipspeed(sh, cap));

    set_level(crew, SK_SAILING, (stype->sumskill - stype->cptskill) * 11);
    set_level(cap, SK_SAILING, stype->cptskill + 10);
    CuAssertIntEquals_Msg(tc, "regular skills should not exceed sh.range", 2, shipspeed(sh, cap));
    test_teardown();
}
Exemple #4
0
static void test_shipspeed_speedy(CuTest *tc) {
    ship_type *stype;
    ship *sh;
    unit *cap, *crw;
    test_setup();
    stype = test_create_shiptype("dragonship");
    stype->range = 5;
    stype->range_max = -1;
    stype->flags |= SFL_SPEEDY;
    cap = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
    crw = test_create_unit(cap->faction, cap->region);
    sh = test_create_ship(cap->region, stype);
    cap->ship = sh;
    crw->ship = sh;
    set_level(cap, SK_SAILING, stype->cptskill);
    set_level(crw, SK_SAILING, stype->sumskill - stype->cptskill);
    CuAssertPtrEquals(tc, cap, ship_owner(sh));
    CuAssertIntEquals(tc, 5, shipspeed(sh, cap));

    set_level(cap, SK_SAILING, stype->cptskill * 3 - 1);
    CuAssertIntEquals(tc, 5, shipspeed(sh, cap));
    set_level(cap, SK_SAILING, stype->cptskill * 3);
    CuAssertIntEquals(tc, 6, shipspeed(sh, cap));

    set_level(cap, SK_SAILING, stype->cptskill * 3 * 3 - 1);
    CuAssertIntEquals(tc, 6, shipspeed(sh, cap));
    set_level(cap, SK_SAILING, stype->cptskill * 3 * 3);
    CuAssertIntEquals(tc, 7, shipspeed(sh, cap));

    test_teardown();
}
Exemple #5
0
static void test_sabotage_other_fail(CuTest *tc) {
    unit *u, *u2;
    region *r;
    order *ord;
    message *msg;

    setup_sabotage();
    r = test_create_region(0, 0, 0);
    assert(r);
    u = test_create_unit(test_create_faction(NULL), r);
    u2 = test_create_unit(test_create_faction(NULL), r);
    assert(u && u2);
    u2->ship = test_create_ship(r, test_create_shiptype("boat"));
    assert(u2->ship);
    u->ship = u2->ship;
    ship_update_owner(u->ship);
    assert(ship_owner(u->ship) == u);
    ord = create_order(K_SABOTAGE, u->faction->locale, "SCHIFF");
    assert(ord);
    CuAssertIntEquals(tc, 0, sabotage_cmd(u2, ord));
    msg = test_get_last_message(u2->faction->msgs);
    CuAssertStrEquals(tc, "destroy_ship_1", test_get_messagetype(msg));
    msg = test_get_last_message(u->faction->msgs);
    CuAssertStrEquals(tc, "destroy_ship_3", test_get_messagetype(msg));
    CuAssertPtrNotNull(tc, r->ships);
    free_order(ord);
    test_cleanup();
}
Exemple #6
0
static void godcurse(void)
{
    region *r;

    for (r = regions; r; r = r->next) {
        if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) {
            unit *u;
            for (u = r->units; u; u = u->next) {
                skill *sv = u->skills;
                while (sv != u->skills + u->skill_size) {
                    int weeks = 1 + rng_int() % 3;
                    reduce_skill(u, sv, weeks);
                    ++sv;
                }
            }
            if (fval(r->terrain, SEA_REGION)) {
                ship *sh;
                for (sh = r->ships; sh;) {
                    ship *shn = sh->next;
                    double dmg = config_get_flt("rules.ship.damage.godcurse", 0.1);
                    damage_ship(sh, dmg);
                    if (sh->damage >= sh->size * DAMAGE_SCALE) {
                        unit *u = ship_owner(sh);
                        if (u)
                            ADDMSG(&u->faction->msgs,
                                   msg_message("godcurse_destroy_ship", "ship", sh));
                        remove_ship(&sh->region->ships, sh);
                    }
                    sh = shn;
                }
            }
        }
    }

}
Exemple #7
0
void leave_ship(unit * u)
{
  struct ship *sh = u->ship;

  u->ship = 0;
  if (sh->_owner==u) {
    ship_update_owner(sh);
    sh->_owner = ship_owner(sh);
  }
  set_leftship(u, sh);
}
Exemple #8
0
static void test_give_control_ship(CuTest * tc)
{
    unit *u1, *u2;
    ship *sh;
    struct faction *f;
    region *r;

    test_cleanup();
    f = test_create_faction(0);
    r = test_create_region(0, 0, 0);
    sh = test_create_ship(r, 0);
    u1 = test_create_unit(f, r);
    u_set_ship(u1, sh);
    u2 = test_create_unit(f, r);
    u_set_ship(u2, sh);
    CuAssertPtrEquals(tc, u1, ship_owner(sh));
    give_control(u1, u2);
    CuAssertPtrEquals(tc, u2, ship_owner(sh));
    test_cleanup();
}
Exemple #9
0
void test_shipowner_goes_to_empty_unit_after_leave(CuTest * tc)
{
    struct region *r;
    struct ship *sh;
    struct unit *u1, *u2, *u3;
    struct faction *f1;
    const struct ship_type *stype;
    const struct race *human;

    test_setup();
    test_create_world();

    human = rc_find("human");
    CuAssertPtrNotNull(tc, human);

    stype = st_find("boat");
    CuAssertPtrNotNull(tc, stype);

    f1 = test_create_faction(human);
    r = findregion(0, 0);

    sh = test_create_ship(r, stype);
    CuAssertPtrNotNull(tc, sh);

    u1 = test_create_unit(f1, r);
    u2 = test_create_unit(f1, r);
    u3 = test_create_unit(f1, r);
    u_set_ship(u1, sh);
    u_set_ship(u2, sh);
    u_set_ship(u3, sh);

    CuAssertPtrEquals(tc, u1, ship_owner(sh));
    u2->number = 0;
    leave_ship(u1);
    CuAssertPtrEquals(tc, u3, ship_owner(sh));
    leave_ship(u3);
    CuAssertPtrEquals(tc, NULL, ship_owner(sh));
    u2->number = 1;
    CuAssertPtrEquals(tc, u2, ship_owner(sh));
    test_teardown();
}
Exemple #10
0
static bool validate_pirate(unit *u, order *ord) {
    if (!u->ship) {
        cmistake(u, ord, 144, MSG_MOVE);
        return false;
    }

    if (!u->ship || u != ship_owner(u->ship)) {
        cmistake(u, ord, 146, MSG_MOVE);
        return false;
    }
    return true;
}
Exemple #11
0
static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc)
{
    struct region *r;
    struct ship *sh;
    struct unit *u, *u2, *u3;
    struct faction *f1, *f2;
    const struct ship_type *stype;
    const struct race *human;

    test_cleanup();
    test_create_world();

    human = rc_find("human");
    CuAssertPtrNotNull(tc, human);

    stype = st_find("boat");
    CuAssertPtrNotNull(tc, stype);

    f1 = test_create_faction(human);
    f2 = test_create_faction(human);
    r = findregion(0, 0);

    sh = test_create_ship(r, stype);
    CuAssertPtrNotNull(tc, sh);

    u2 = test_create_unit(f2, r);
    u3 = test_create_unit(f1, r);
    u = test_create_unit(f1, r);
    CuAssertPtrNotNull(tc, u);
    u_set_ship(u, sh);
    u_set_ship(u2, sh);
    u_set_ship(u3, sh);
    CuAssertPtrEquals(tc, u, ship_owner(sh));
    leave_ship(u);
    CuAssertPtrEquals(tc, u3, ship_owner(sh));
    leave_ship(u3);
    CuAssertPtrEquals(tc, u2, ship_owner(sh));
    leave_ship(u2);
    CuAssertPtrEquals(tc, 0, ship_owner(sh));
}
Exemple #12
0
static void test_sabotage_other_success(CuTest *tc) {
    unit *u, *u2;
    region *r;
    order *ord;

    setup_sabotage();
    r = test_create_region(0, 0, 0);
    assert(r);
    u = test_create_unit(test_create_faction(NULL), r);
    u2 = test_create_unit(test_create_faction(NULL), r);
    assert(u && u2);
    u2->ship = test_create_ship(r, test_create_shiptype("boat"));
    assert(u2->ship);
    u->ship = u2->ship;
    ship_update_owner(u->ship);
    assert(ship_owner(u->ship) == u);
    ord = create_order(K_SABOTAGE, u->faction->locale, "SCHIFF");
    assert(ord);
    set_level(u2, SK_SPY, 1);
    CuAssertIntEquals(tc, 0, sabotage_cmd(u2, ord));
    CuAssertPtrEquals(tc, 0, r->ships);
    free_order(ord);
    test_cleanup();
}
Exemple #13
0
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));
        }
    }
  }
}
Exemple #14
0
void piracy_cmd(unit * u, order *ord)
{
    region *r = u->region;
    ship *sh = u->ship, *sh2;
    direction_t target_dir;
    struct {
        const faction *target;
        int value;
    } aff[MAXDIRECTIONS];
    int saff = 0;
    int *il;

    if (!validate_pirate(u, ord)) {
        return;
    }

    il = parse_ids(ord);
    /* Feststellen, ob schon ein anderer alliierter Pirat ein
    * Ziel gefunden hat. */

    target_dir = find_piracy_target(u, il);

    /* Wenn nicht, sehen wir, ob wir ein Ziel finden. */

    if (target_dir == NODIRECTION) {
        direction_t dir;
        /* Einheit ist also Kapitän. Jetzt gucken, in wievielen
        * Nachbarregionen potentielle Opfer sind. */

        for (dir = 0; dir < MAXDIRECTIONS; dir++) {
            region *rc = rconnect(r, dir);
            aff[dir].value = 0;
            aff[dir].target = 0;
            if (rc && fval(rc->terrain, SAIL_INTO) && can_takeoff(sh, r, rc)) {

                for (sh2 = rc->ships; sh2; sh2 = sh2->next) {
                    unit *cap = ship_owner(sh2);
                    if (cap) {
                        faction *f = visible_faction(cap->faction, cap);
                        if (alliedunit(u, f, HELP_FIGHT))
                            continue;
                        if (!il || intlist_find(il, cap->faction->no)) { // TODO: shouldn't this be f->no?
                            ++aff[dir].value;
                            if (rng_int() % aff[dir].value == 0) {
                                aff[dir].target = f;
                            }
                        }
                    }
                }

                /* Und aufaddieren. */
                saff += aff[dir].value;
            }
        }

        if (saff != 0) {
            saff = rng_int() % saff;
            for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
                if (saff < aff[dir].value) {
                    target_dir = dir;
                    a_add(&r->attribs, mk_piracy(u->faction, aff[dir].target, target_dir));
                    break;
                }
                saff -= aff[dir].value;
            }
        }
    }

    free(il);

    /* Wenn kein Ziel gefunden, entsprechende Meldung generieren */
    if (target_dir == NODIRECTION) {
        ADDMSG(&u->faction->msgs, msg_message("piratenovictim",
            "ship region", sh, r));
        return;
    }

    /* Meldung generieren */
    ADDMSG(&u->faction->msgs, msg_message("piratesawvictim",
        "ship region dir", sh, r, target_dir));

    /* Befehl konstruieren */
    set_order(&u->thisorder, create_order(K_MOVE, u->faction->locale, "%s",
        LOC(u->faction->locale, directions[target_dir])));

    /* Bewegung ausführen */
    init_order(u->thisorder);
    move_cmd(u, true);
}
Exemple #15
0
int shipspeed(const ship * sh, const unit * u)
{
    int k = sh->type->range;
    static const struct curse_type *stormwind_ct, *nodrift_ct;
    static bool init;
    attrib *a;
    struct curse *c;
    int bonus;

    assert(sh);
    if (!u) u = ship_owner(sh);
    if (!u) return 0;
    assert(u->ship == sh);
    assert(u == ship_owner(sh));
    assert(sh->type->construction);
    assert(sh->type->construction->improvement == NULL);  /* sonst ist construction::size nicht ship_type::maxsize */

    if (!init) {
        init = true;
        stormwind_ct = ct_find("stormwind");
        nodrift_ct = ct_find("nodrift");
    }
    if (sh->size != sh->type->construction->maxsize)
        return 0;

    if (curse_active(get_curse(sh->attribs, stormwind_ct)))
        k *= 2;
    if (curse_active(get_curse(sh->attribs, nodrift_ct)))
        k += 1;

    if (u->faction->race == u_race(u)) {
        /* race bonus for this faction? */
        if (fval(u_race(u), RCF_SHIPSPEED)) {
            k += 1;
        }
    }

    bonus = ShipSpeedBonus(u);
    if (bonus > 0 && sh->type->range_max>sh->type->range) {
        int crew = crew_skill(sh);
        int crew_bonus = (crew / sh->type->sumskill / 2) - 1;
        if (crew_bonus > 0) {
            bonus = _min(bonus, crew_bonus);
            bonus = _min(bonus, sh->type->range_max - sh->type->range);
        }
        else {
            bonus = 0;
        }
    }
    k += bonus;

    a = a_find(sh->attribs, &at_speedup);
    while (a != NULL && a->type == &at_speedup) {
        k += a->data.sa[0];
        a = a->next;
    }

    c = get_curse(sh->attribs, ct_find("shipspeedup"));
    while (c) {
        k += curse_geteffect_int(c);
        c = c->nexthash;
    }

    if (sh->damage>0) {
        int size = sh->size * DAMAGE_SCALE;
        k *= (size - sh->damage);
        k = (k + size - 1) / size;
    }
    return k;
}
Exemple #16
0
int shipspeed(const ship * sh, const unit * u)
{
    attrib *a;
    struct curse *c;
    int k, bonus;

    assert(sh);
    if (!u) u = ship_owner(sh);
    if (!u) return 0;
    assert(u->ship == sh);
    assert(u == ship_owner(sh));
    assert(sh->type->construction);

    k = sh->type->range;
    if (sh->size != sh->type->construction->maxsize)
        return 0;

    if (sh->attribs) {
        if (curse_active(get_curse(sh->attribs, &ct_stormwind))) {
            k *= 2;
        }
        if (curse_active(get_curse(sh->attribs, &ct_nodrift))) {
            k += 1;
        }
    }
    if (u->faction->race == u_race(u)) {
        /* race bonus for this faction? */
        if (fval(u_race(u), RCF_SHIPSPEED)) {
            k += 1;
        }
    }

    bonus = ShipSpeedBonus(u);
    if (bonus > 0 && sh->type->range_max > sh->type->range) {
        int crew = crew_skill(sh);
        int crew_bonus = (crew / sh->type->sumskill / 2) - 1;
        if (crew_bonus > 0) {
            int sbonus = sh->type->range_max - sh->type->range;
            if (bonus > sbonus) bonus = sbonus;
            if (bonus > crew_bonus) bonus = crew_bonus;
        }
        else {
            bonus = 0;
        }
    }
    k += bonus;

    a = a_find(sh->attribs, &at_speedup);
    while (a != NULL && a->type == &at_speedup) {
        k += a->data.sa[0];
        a = a->next;
    }

    c = get_curse(sh->attribs, &ct_shipspeedup);
    while (c) {
        k += curse_geteffect_int(c);
        c = c->nexthash;
    }

    if (sh->damage > 0) {
        int size = sh->size * DAMAGE_SCALE;
        k *= (size - sh->damage);
        k = (k + size - 1) / size;
    }
    return k;
}
Exemple #17
0
int destroy_cmd(unit * u, struct order *ord)
{
    char token[128];
    ship *sh;
    unit *u2;
    region *r = u->region;
    const construction *con = NULL;
    int size = 0;
    const char *s;
    int n = INT_MAX;

    if (u->number < 1)
        return 0;

    init_order(ord);
    s = gettoken(token, sizeof(token));

    if (findparam(s, u->faction->locale) == P_ROAD) {
        destroy_road(u, INT_MAX, ord);
        return 0;
    }

    if (s && *s) {
        n = atoi((const char *)s);
        if (n <= 0) {
            cmistake(u, ord, 288, MSG_PRODUCE);
            return 0;
        }
    }

    if (getparam(u->faction->locale) == P_ROAD) {
        destroy_road(u, n, ord);
        return 0;
    }

    if (u->building) {
        building *b = u->building;

        if (u != building_owner(b)) {
            cmistake(u, ord, 138, MSG_PRODUCE);
            return 0;
        }
        if (fval(b->type, BTF_INDESTRUCTIBLE)) {
            cmistake(u, ord, 138, MSG_PRODUCE);
            return 0;
        }
        if (n >= b->size) {
            /* destroy completly */
            /* all units leave the building */
            for (u2 = r->units; u2; u2 = u2->next) {
                if (u2->building == b) {
                    leave_building(u2);
                }
            }
            ADDMSG(&u->faction->msgs, msg_message("destroy", "building unit", b, u));
            con = b->type->construction;
            remove_building(&r->buildings, b);
        }
        else {
            /* partial destroy */
            b->size -= n;
            ADDMSG(&u->faction->msgs, msg_message("destroy_partial",
                "building unit", b, u));
        }
    }
    else if (u->ship) {
        sh = u->ship;

        if (u != ship_owner(sh)) {
            cmistake(u, ord, 138, MSG_PRODUCE);
            return 0;
        }
        if (fval(r->terrain, SEA_REGION)) {
            cmistake(u, ord, 14, MSG_EVENT);
            return 0;
        }

        if (n >= (sh->size * 100) / sh->type->construction->maxsize) {
            /* destroy completly */
            /* all units leave the ship */
            for (u2 = r->units; u2; u2 = u2->next) {
                if (u2->ship == sh) {
                    leave_ship(u2);
                }
            }
            ADDMSG(&u->faction->msgs, msg_message("shipdestroy",
                "unit region ship", u, r, sh));
            con = sh->type->construction;
            remove_ship(&sh->region->ships, sh);
        }
        else {
            /* partial destroy */
            sh->size -= (sh->type->construction->maxsize * n) / 100;
            ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial",
                "unit region ship", u, r, sh));
        }
    }
    else {
        cmistake(u, ord, 138, MSG_PRODUCE);
        return 0;
    }

    if (con) {
        /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */
        int c;
        for (c = 0; con->materials[c].number; ++c) {
            const requirement *rq = con->materials + c;
            int recycle = (rq->number * size / con->reqsize) / 2;
            if (recycle) {
                change_resource(u, rq->rtype, recycle);
            }
        }
    }
    return 0;
}