Exemple #1
0
faction *gm_addfaction(const char *email, plane * p, region * r)
{
  attrib *a;
  unit *u;
  faction *f = calloc(1, sizeof(faction));

  assert(p != NULL);

  /* GM faction */
  a_add(&f->attribs, make_key(atoi36("quest")));
  f->banner = _strdup("quest faction");
  f->name = _strdup("quest faction");
  f->passw = _strdup(itoa36(rng_int()));
  if (set_email(&f->email, email) != 0) {
    log_error("Invalid email address for faction %s: %s\n", itoa36(f->no), email);
  }
  f->race = new_race[RC_TEMPLATE];
  f->age = 0;
  f->lastorders = turn;
  f->alive = true;
  f->locale = default_locale;
  f->options =
    want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN);
  {
    faction *xist;
    int id = atoi36("gm00") - 1;
    do {
      xist = findfaction(++id);
    } while (xist);

    f->no = id;
    addlist(&factions, f);
    fhash(f);
  }

  /* generic permissions */
  a = a_add(&f->attribs, a_new(&at_permissions));
  if (a) {
    attrib *ap = (attrib *) a->data.v;
    const char *keys[] =
      { "gmterf", "gmtele", "gmgive", "gmskil", "gmtake", "gmmsgr", "gmmsgu",
        "gmgate", 0 };
    const char **key_p = keys;
    while (*key_p) {
      add_key(&ap, atoi36(*key_p));
      ++key_p;
    }
    a_add(&ap, make_atgmcreate(resource2item(r_silver)));

    a->data.v = ap;
  }

  /* one initial unit */
  u = create_unit(r, f, 1, new_race[RC_TEMPLATE], 1, "quest master", NULL);
  u->irace = new_race[RC_GNOME];

  return f;
}
static void test_forbiddenid(CuTest *tc) {
    CuAssertIntEquals(tc, 0, forbiddenid(1));
    CuAssertIntEquals(tc, 1, forbiddenid(0));
    CuAssertIntEquals(tc, 1, forbiddenid(-1));
    CuAssertIntEquals(tc, 1, forbiddenid(atoi36("temp")));
    CuAssertIntEquals(tc, 1, forbiddenid(atoi36("tem")));
    CuAssertIntEquals(tc, 1, forbiddenid(atoi36("te")));
    CuAssertIntEquals(tc, 1, forbiddenid(atoi36("t")));
}
Exemple #3
0
static void test_atoi36(CuTest * tc)
{
  CuAssertIntEquals(tc, 0, atoi36("0"));
  CuAssertIntEquals(tc, 666, atoi36("ii"));
  CuAssertIntEquals(tc, -10, atoi36("-a"));
  CuAssertIntEquals(tc, -1, atoi36("-1"));
  CuAssertIntEquals(tc, -10, atoi("-10"));
  CuAssertIntEquals(tc, -10, atoi("-10"));
}
Exemple #4
0
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.");
}
Exemple #5
0
/**
 ** 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);
    }
  }
}
Exemple #6
0
/**
 ** 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);
  }
}
Exemple #7
0
/**
 ** 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);
  }
}
Exemple #8
0
/**
 ** 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);
      }
    }
  }
}
Exemple #9
0
/**
 ** 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.");
}
Exemple #10
0
/**
 ** 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);
    }
  }
}
Exemple #11
0
static struct quicklist *
read_factions(sqlite3 * db, int game_id) {
    int res;
    quicklist *result = 0;
    const char * sql =
        "SELECT f.id, fd.code, fd.name, fd.email FROM faction f"
        " LEFT OUTER JOIN faction_data fd"
        " WHERE f.id=fd.faction_id AND f.game_id=? AND"
        " fd.turn=(SELECT MAX(turn) FROM faction_data fx WHERE fx.faction_id=f.id)"
        " ORDER BY f.id";
    sqlite3_stmt *stmt = 0;
    sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
    sqlite3_bind_int(stmt, 1, game_id);

    res = sqlite3_step(stmt);
    while (res == SQLITE_ROW) {
        const char * text;
        db_faction * dbf = (db_faction*)calloc(1, sizeof(db_faction));
        dbf->uid = (int)sqlite3_column_int64(stmt, 0);
        text = (const char *)sqlite3_column_text(stmt, 1);
        if (text) dbf->no = atoi36(text);
        text = (const char *)sqlite3_column_text(stmt, 2);
        if (text) dbf->name = _strdup(text);
        text = (const char *)sqlite3_column_text(stmt, 3);
        if (text) dbf->email = _strdup(text);
        ql_push(&result, dbf);
        res = sqlite3_step(stmt);
    }
    sqlite3_finalize(stmt);
    return result;
}
Exemple #12
0
/**
 ** 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);
      }
    }
  }
}
Exemple #13
0
/**
 ** 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));
    }
  }
}
Exemple #14
0
static int tolua_region_getkey(lua_State * L)
{
    region *self = (region *)tolua_tousertype(L, 1, 0);
    const char *name = tolua_tostring(L, 2, 0);
    int flag = atoi36(name);

    lua_pushboolean(L, key_get(self->attribs, flag));
    return 1;
}
Exemple #15
0
int getid(void)
{
    char token[8];
    const char *str = gettoken(token, sizeof(token));
    int i = str ? atoi36(str) : 0;
    if (i < 0) {
        return -1;
    }
    return i;
}
Exemple #16
0
static int
use_museumexitticket(unit * u, const struct item_type *itype, int amount,
order * ord)
{
    attrib *a;
    region *r;
    unit *warden = findunit(atoi36("mwar"));
    int unit_cookie;

    unused_arg(amount);

    /* Prüfen ob in Eingangshalle */
    if (u->region->x != 9525 || u->region->y != 9525) {
        cmistake(u, ord, 266, MSG_MAGIC);
        return 0;
    }

    a = a_find(u->attribs, &at_museumexit);
    assert(a);
    r = findregion(a->data.sa[0], a->data.sa[1]);
    assert(r);
    a_remove(&u->attribs, a);
    /* Übergebene Gegenstände zurückgeben */

    a = a_find(u->attribs, &at_museumgivebackcookie);
    if (a) {
        unit_cookie = a->data.i;
        a_remove(&u->attribs, a);

        for (a = a_find(warden->attribs, &at_museumgiveback);
            a && a->type == &at_museumgiveback; a = a->next) {
            if (((museumgiveback *)(a->data.v))->cookie == unit_cookie)
                break;
        }
        if (a && a->type == &at_museumgiveback) {
            museumgiveback *gb = (museumgiveback *)(a->data.v);
            item *it;

            for (it = gb->items; it; it = it->next) {
                i_change(&u->items, it->type, it->number);
            }
            ADDMSG(&u->faction->msgs, msg_message("museumgiveback",
                "region unit sender items", r, u, warden, gb->items));
            a_remove(&warden->attribs, a);
        }
    }

    /* Benutzer zurück teleportieren */
    move_unit(u, r, NULL);

    /* Exitticket abziehen */
    i_change(&u->items, itype, -1);

    return 0;
}
Exemple #17
0
static void test_upgrade_dict(CuTest *tc) {
    attrib *a;
    
    a = a_new(&at_dict);

    dict_set(a, "embassy_muschel", 42);
    CuAssertPtrNotNull(tc, a->type->upgrade);
    a->type->upgrade(&a, a);
    CuAssertIntEquals(tc, 42, key_get(a, atoi36("mupL")));
    a_removeall(&a, NULL);
}
Exemple #18
0
int tolua_toid(lua_State * L, int idx, int def)
{
    int no = 0;
    int type = lua_type(L, idx);
    if (type == LUA_TNUMBER) {
        no = (int)tolua_tonumber(L, idx, def);
    }
    else {
        const char *str = tolua_tostring(L, idx, NULL);
        no = str ? atoi36(str) : def;
    }
    return no;
}
Exemple #19
0
int *parse_ids(const order *ord) {
    const char *s;
    int *il = NULL;

    init_order(ord);
    s = getstrtoken();
    if (s != NULL && *s) {
        il = intlist_init();
        while (s && *s) {
            il = intlist_add(il, atoi36(s));
            s = getstrtoken();
        }
    }
    return il;
}
Exemple #20
0
static int tolua_region_setkey(lua_State * L)
{
    region *self = (region *)tolua_tousertype(L, 1, 0);
    const char *name = tolua_tostring(L, 2, 0);
    int value = tolua_toboolean(L, 3, 0);
    int flag = atoi36(name);

    if (value) {
        key_set(&self->attribs, flag);
    }
    else {
        key_unset(&self->attribs, flag);
    }
    return 0;
}
Exemple #21
0
static int tolua_region_setkey(lua_State * L)
{
  region *self = (region *) tolua_tousertype(L, 1, 0);
  const char *name = tolua_tostring(L, 2, 0);
  int value = tolua_toboolean(L, 3, 0);

  int flag = atoi36(name);
  attrib *a = find_key(self->attribs, flag);
  if (a == NULL && value) {
    add_key(&self->attribs, flag);
  } else if (a != NULL && !value) {
    a_remove(&self->attribs, a);
  }
  return 0;
}
Exemple #22
0
static void test_getunit(CuTest *tc) {
    unit *u, *u2;
    order *ord;
    attrib *a;
    struct region *r;
    struct locale *lang;
    struct terrain_type *t_plain;

    test_cleanup();
    lang = get_or_create_locale("de");
    test_translate_param(lang, P_TEMP, "TEMP");
    /* note that the english order is FIGHT, not COMBAT, so this is a poor example */
    t_plain = test_create_terrain("plain", LAND_REGION);
    u = test_create_unit(test_create_faction(0), test_create_region(0, 0, t_plain));
    a = a_add(&u->attribs, a_new(&at_alias));
    a->data.i = atoi36("42"); /* this unit is also TEMP 42 */
    r = test_create_region(1, 0, t_plain);

    ord = create_order(K_GIVE, lang, itoa36(u->no));
    init_order(ord);
    CuAssertIntEquals(tc, GET_UNIT, getunit(u->region, u->faction, &u2));
    CuAssertPtrEquals(tc, u, u2);
    init_order(ord);
    CuAssertIntEquals(tc, GET_NOTFOUND, getunit(r, u->faction, &u2));
    CuAssertPtrEquals(tc, NULL, u2);
    free_order(ord);

    ord = create_order(K_GIVE, lang, itoa36(u->no + 1));
    init_order(ord);
    CuAssertIntEquals(tc, GET_NOTFOUND, getunit(u->region, u->faction, &u2));
    CuAssertPtrEquals(tc, NULL, u2);
    free_order(ord);

    ord = create_order(K_GIVE, lang, "0");
    init_order(ord);
    CuAssertIntEquals(tc, GET_PEASANTS, getunit(u->region, u->faction, &u2));
    CuAssertPtrEquals(tc, NULL, u2);
    free_order(ord);

    ord = create_order(K_GIVE, lang, "TEMP 42");
    init_order(ord);
    CuAssertIntEquals(tc, GET_UNIT, getunit(u->region, u->faction, &u2));
    CuAssertPtrEquals(tc, u, u2);
    free_order(ord);

    test_cleanup();
}
static void test_read_unitid(CuTest *tc) {
    unit *u;
    order *ord;
    attrib *a;
    struct locale *lang;
    struct terrain_type *t_plain;

    test_cleanup();
    lang = get_or_create_locale("de");
    test_translate_param(lang, P_TEMP, "TEMP");
    /* note that the english order is FIGHT, not COMBAT, so this is a poor example */
    t_plain = test_create_terrain("plain", LAND_REGION);
    u = test_create_unit(test_create_faction(0), test_create_region(0, 0, t_plain));
    a = a_add(&u->attribs, a_new(&at_alias));
    a->data.i = atoi36("42"); /* this unit is also TEMP 42 */

    ord = create_order(K_GIVE, lang, "TEMP 42");
    init_order(ord);
    CuAssertIntEquals(tc, u->no, read_unitid(u->faction, u->region));
    free_order(ord);

    ord = create_order(K_GIVE, lang, "8");
    init_order(ord);
    CuAssertIntEquals(tc, 8, read_unitid(u->faction, u->region));
    free_order(ord);

    ord = create_order(K_GIVE, lang, "");
    init_order(ord);
    CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region));
    free_order(ord);

    ord = create_order(K_GIVE, lang, "TEMP");
    init_order(ord);
    CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region));
    free_order(ord);

    // bug https://bugs.eressea.de/view.php?id=1685
    ord = create_order(K_GIVE, lang, "##");
    init_order(ord);
    CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region));
    free_order(ord);

    test_cleanup();
}
Exemple #24
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));
    }
  }
}
Exemple #25
0
/**
 ** 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));
    }
  }
}
Exemple #26
0
static bool has_permission(const attrib * permissions, unsigned int key)
{
  return (find_key((attrib *) permissions->data.v, key) ||
    find_key((attrib *) permissions->data.v, atoi36("master")));
}
Exemple #27
0
int db_update_factions(sqlite3 * db, bool force)
{
  int game_id = 6;
  const char sql_select[] =
    "SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction"
    " WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)";
  sqlite3_stmt *stmt_select = stmt_cache_get(db, sql_select);
  faction *f;
  int res;

  res = sqlite3_bind_int(stmt_select, 1, game_id);
  SQL_EXPECT(res, SQLITE_OK);
  res = sqlite3_bind_int(stmt_select, 2, turn - 2);
  SQL_EXPECT(res, SQLITE_OK);
  for (;;) {
    sqlite3_uint64 id_faction;
    int lastturn;

    res = sqlite3_step(stmt_select);
    if (res != SQLITE_ROW)
      break;

    id_faction = sqlite3_column_int64(stmt_select, 0);
    lastturn = sqlite3_column_int(stmt_select, 6);
    f = get_faction_by_id((int)id_faction);

    if (f == NULL || !f->alive) {
      if (lastturn == 0) {
        const char sql_update[] = "UPDATE faction SET lastturn=? WHERE id=?";
        sqlite3_stmt *stmt = stmt_cache_get(db, sql_update);

        lastturn = f ? f->lastorders : turn - 1;
        sqlite3_bind_int(stmt, 1, lastturn);
        sqlite3_bind_int64(stmt, 2, id_faction);
        res = sqlite3_step(stmt);
        SQL_EXPECT(res, SQLITE_DONE);
      }
    } else {
      md5_state_t ms;
      md5_byte_t digest[16];
      int i;
      char passwd_md5[MD5_LENGTH_0];
      sqlite3_uint64 id_email;
      bool update = force;
      db_faction dbstate;
      const char *no_b36;

      fset(f, FFL_MARK);
      dbstate.id_faction = id_faction;
      dbstate.id_email = sqlite3_column_int64(stmt_select, 1);
      no_b36 = (const char *)sqlite3_column_text(stmt_select, 2);
      dbstate.no = no_b36 ? atoi36(no_b36) : -1;
      dbstate.email = (const char *)sqlite3_column_text(stmt_select, 3);
      dbstate.passwd_md5 = (const char *)sqlite3_column_text(stmt_select, 4);
      dbstate.name = (const char *)sqlite3_column_text(stmt_select, 5);

      id_email = dbstate.id_email;
      res = db_update_email(db, f, &dbstate, force, &id_email);
      SQL_EXPECT(res, SQLITE_OK);

      md5_init(&ms);
      md5_append(&ms, (md5_byte_t *) f->passw, (int)strlen(f->passw));
      md5_finish(&ms, digest);
      for (i = 0; i != 16; ++i)
        sprintf(passwd_md5 + 2 * i, "%.02x", digest[i]);

      if (!update) {
        update = ((id_email != 0 && dbstate.id_email != id_email)
          || dbstate.no != f->no || dbstate.passwd_md5 == NULL
          || strcmp(passwd_md5, dbstate.passwd_md5) != 0 || dbstate.name == NULL
          || strncmp(f->name, dbstate.name, MAX_FACTION_NAME) != 0);
      }
      if (update) {
        const char sql_update_faction[] =
          "UPDATE faction SET email_id=?, password_md5=?, code=?, name=?, firstturn=? WHERE id=?";
        sqlite3_stmt *stmt_update_faction =
          stmt_cache_get(db, sql_update_faction);

        res = sqlite3_bind_int64(stmt_update_faction, 1, id_email);
        SQL_EXPECT(res, SQLITE_OK);
        res =
          sqlite3_bind_text(stmt_update_faction, 2, passwd_md5, MD5_LENGTH,
          SQLITE_TRANSIENT);
        SQL_EXPECT(res, SQLITE_OK);
        res =
          sqlite3_bind_text(stmt_update_faction, 3, no_b36, -1,
          SQLITE_TRANSIENT);
        SQL_EXPECT(res, SQLITE_OK);
        res =
          sqlite3_bind_text(stmt_update_faction, 4, f->name, -1,
          SQLITE_TRANSIENT);
        SQL_EXPECT(res, SQLITE_OK);
        res = sqlite3_bind_int(stmt_update_faction, 5, turn - f->age);
        SQL_EXPECT(res, SQLITE_OK);
        res = sqlite3_bind_int64(stmt_update_faction, 6, f->subscription);
        SQL_EXPECT(res, SQLITE_OK);
        res = sqlite3_step(stmt_update_faction);
        SQL_EXPECT(res, SQLITE_DONE);
      }
    }
  }

  for (f = factions; f; f = f->next) {
    if (!fval(f, FFL_MARK)) {
      log_error("%s (sub=%d, email=%s) has no entry in the database\n", factionname(f), f->subscription, f->email);
    } else {
      freset(f, FFL_MARK);
    }
  }
  return SQLITE_OK;
}