diff --git a/scripts/eressea/equipment.lua b/scripts/eressea/equipment.lua index 7d92d43c9..3163b85d9 100644 --- a/scripts/eressea/equipment.lua +++ b/scripts/eressea/equipment.lua @@ -6,10 +6,6 @@ local function equip_first(u) equip_unit(u, name, 255) end -local function equip_demon(u) - u.race_name = 'human' -end - local mysets = { ['first_unit'] = { ['items'] = { @@ -82,7 +78,6 @@ local mysets = { ['skills'] = { ['stamina'] = 15 }, - ['callback'] = equip_demon }, ['seed_insect'] = { ['items'] = { diff --git a/src/battle.c b/src/battle.c index a0e03f1f9..08d268224 100644 --- a/src/battle.c +++ b/src/battle.c @@ -300,15 +300,16 @@ fighter *select_corpse(battle * b, fighter * af) /* Geflohene haben auch 0 hp, duerfen hier aber nicht ausgewaehlt * werden! */ int dead = dead_fighters(df); - if (!playerrace(u_race(df->unit))) - continue; - - if (af && !helping(af->side, df->side)) - continue; - if (di < dead) { - return df; + const race *rc = u_race(df->unit); + /* Untote sinc für immer tot */ + if (!undeadrace(rc)) { + if (af && !helping(af->side, df->side)) + continue; + if (di < dead) { + return df; + } + di -= dead; } - di -= dead; } } } @@ -2076,9 +2077,6 @@ static void make_heroes(battle * b) unit *u = fig->unit; if (fval(u, UFL_HERO)) { int i; - if (!playerrace(u_race(u))) { - log_error("Hero %s is a %s.\n", unitname(u), u_race(u)->_name); - } for (i = 0; i != u->number; ++i) { fig->person[i].speed += (rule_hero_speed - 1); } @@ -2609,11 +2607,12 @@ static void aftermath(battle * b) for (df = s->fighters; df; df = df->next) { unit *du = df->unit; int dead = dead_fighters(df); + const race *rc = u_race(du); /* tote insgesamt: */ s->dead += dead; /* Tote, die wiederbelebt werde koennen: */ - if (playerrace(u_race(df->unit))) { + if (!undeadrace(rc)) { s->casualties += dead; } if (df->hits + df->kills) { @@ -2640,6 +2639,7 @@ static void aftermath(battle * b) for (df = s->fighters; df; df = df->next) { unit *du = df->unit; + const race *rc = u_race(du); int dead = dead_fighters(df); int sum_hp = 0; int n; @@ -2732,7 +2732,7 @@ static void aftermath(battle * b) } s->flee += df->run.number; - if (playerrace(u_race(du))) { + if (!undeadrace(rc)) { /* tote im kampf werden zu regionsuntoten: * for each of them, a peasant will die as well */ dead_players += dead; @@ -3102,7 +3102,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) } else { building *bld = u->building; - if (bld && bld->sizeleft >= u->number && playerrace(u_race(u))) { + if (bld && bld->sizeleft >= u->number && humanoidrace(u_race(u))) { fig->building = bld; fig->building->sizeleft -= u->number; } diff --git a/src/chaos.c b/src/chaos.c index 2639592f0..fed9a5f49 100644 --- a/src/chaos.c +++ b/src/chaos.c @@ -83,7 +83,7 @@ static void chaos(region * r) case 0: /* Untote */ if (!(r->terrain->flags & SEA_REGION)) { unit *u = random_unit(r); - if (u && playerrace(u_race(u))) { + if (u && !undeadrace(u_race(u))) { ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); u_setfaction(u, get_monsters()); u_freeorders(u); diff --git a/src/creport.c b/src/creport.c index f9bffd177..ddfe1247c 100644 --- a/src/creport.c +++ b/src/creport.c @@ -769,6 +769,7 @@ static void cr_output_spells(stream *out, const unit * u, int maxlevel) void cr_output_unit(stream *out, const faction * f, const unit * u, seen_mode mode) { + const struct locale *lang = crtag_locale(); /* Race attributes are always plural and item attributes always * singular */ const char *str; @@ -781,7 +782,6 @@ void cr_output_unit(stream *out, const faction * f, const faction *fother; const char *prefix; bool allied; - const struct locale *lang = f->locale; assert(u && u->number); @@ -841,17 +841,16 @@ void cr_output_unit(stream *out, const faction * f, pzTmp = get_racename(u->attribs); if (pzTmp) { - const char *pzRace = locale_string(lang, mkname("race", pzTmp), false); - if (pzRace) { - pzTmp = pzRace; + const char *pzRace = pzTmp; + const struct race *rc = rc_find(pzTmp); + if (rc) { + pzRace = rc_name_s(rc, NAME_PLURAL); } - pzRace = translate(pzTmp, locale_string(lang, pzTmp, false)); - if (!pzRace) { - pzRace = pzTmp; - } - stream_printf(out, "\"%s\";Typ\n", pzRace); - if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { - pzRace = rc_name_s(u_race(u), NAME_PLURAL); + pzTmp = translate(pzRace, locale_string(lang, pzRace, false)); + stream_printf(out, "\"%s\";Typ\n", pzTmp); + rc = u_race(u); + if (u->faction == f && fval(rc, RCF_SHAPESHIFTANY)) { + pzRace = rc_name_s(rc, NAME_PLURAL); stream_printf(out, "\"%s\";wahrerTyp\n", pzRace); } } @@ -1559,7 +1558,7 @@ static void report_itemtype(FILE *F, faction *f, const item_type *itype) { static int report_computer(const char *filename, report_context * ctx, const char *bom) { - static int era = -1; + const struct locale *lang = crtag_locale(); int i; faction *f = ctx->f; const char *prefix, *str; @@ -1569,6 +1568,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) FILE *F = fopen(filename, "w"); static const race *rc_human; static int rc_cache; + static int era = -1; if (era < 0) { era = config_get_int("game.era", 1); @@ -1623,13 +1623,13 @@ report_computer(const char *filename, report_context * ctx, const char *bom) } { const char *zRace = rc_name_s(f->race, NAME_PLURAL); - fprintf(F, "\"%s\";Typ\n", translate(zRace, LOC(f->locale, zRace))); + fprintf(F, "\"%s\";Typ\n", translate(zRace, LOC(lang, zRace))); } prefix = get_prefix(f->attribs); if (prefix != NULL) { prefix = mkname("prefix", prefix); fprintf(F, "\"%s\";typprefix\n", - translate(prefix, LOC(f->locale, prefix))); + translate(prefix, LOC(lang, prefix))); } fprintf(F, "%d;Rekrutierungskosten\n", f->race->recruitcost); fprintf(F, "%d;Anzahl Personen\n", f->num_people); @@ -1682,7 +1682,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) if (prefix != NULL) { prefix = mkname("prefix", prefix); fprintf(F, "\"%s\";typprefix\n", - translate(prefix, LOC(f->locale, prefix))); + translate(prefix, LOC(lang, prefix))); } show_allies_cr(F, f, g); } diff --git a/src/creport.test.c b/src/creport.test.c index b536a7114..53b2e9d93 100644 --- a/src/creport.test.c +++ b/src/creport.test.c @@ -4,6 +4,13 @@ #include "spy.h" #include "travelthru.h" +#include "attributes/racename.h" + +#include "util/keyword.h" +#include +#include +#include + #include #include #include @@ -16,11 +23,6 @@ #include #include -#include "util/keyword.h" -#include -#include -#include - #include #include @@ -222,6 +224,96 @@ static int cr_get_int(stream *strm, const char *match, int def) return def; } +static bool cr_find_string(stream *strm, const char *match, const char *value) +{ + char line[1024]; + size_t len = strlen(match); + + strm->api->rewind(strm->handle); + while (strm->api->readln(strm->handle, line, sizeof(line))==0) { + if (line[0] == '\"') { + const char * pos = strstr(line + 1, match); + if (pos && pos[len] == '\0') { + size_t vlen = strlen(value); + if (value != NULL && strncmp(line + 1, value, vlen) == 0) { + return (line[vlen + 1] == '\"'); + } + return false; + } + } + } + return value == NULL; +} + +static void test_cr_hiderace(CuTest *tc) { + stream strm; + faction *f1, *f2; + region *r; + unit *u; + struct locale * lang; + + test_setup(); + default_locale = test_create_locale(); + locale_setstring(default_locale, "race::elf_p", "Elfen"); + locale_setstring(default_locale, "race::elf", "elf"); + locale_setstring(default_locale, "race::human_p", "Menschen"); + locale_setstring(default_locale, "race::human", "Mensch"); + lang = get_or_create_locale("en"); + locale_setstring(lang, "race::human_p", "humans"); + locale_setstring(lang, "race::human", "human"); + locale_setstring(lang, "race::elf_p", "elves"); + locale_setstring(lang, "race::elf", "elf"); + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); + u = test_create_unit(f1, r); + + mstream_init(&strm); + CuAssertPtrEquals(tc, default_locale, (struct locale *)f1->locale); + CuAssertPtrEquals(tc, default_locale, (struct locale *)f2->locale); + cr_output_unit(&strm, f1, u, seen_unit); + CuAssertTrue(tc, cr_find_string(&strm, ";Typ", "Menschen")); + CuAssertTrue(tc, cr_find_string(&strm, ";wahrerTyp", NULL)); + mstream_done(&strm); + mstream_init(&strm); + CuAssertPtrEquals(tc, default_locale, (struct locale *)f1->locale); + CuAssertPtrEquals(tc, default_locale, (struct locale *)f2->locale); + cr_output_unit(&strm, f2, u, seen_unit); + CuAssertTrue(tc, cr_find_string(&strm, ";Typ", "Menschen")); + CuAssertTrue(tc, cr_find_string(&strm, ";wahrerTyp", NULL)); + mstream_done(&strm); + + /* when we use irace, the owner can see the true race */ + f1->locale = lang; + u->irace = test_create_race("elf"); + mstream_init(&strm); + cr_output_unit(&strm, f1, u, seen_unit); + CuAssertTrue(tc, cr_find_string(&strm, ";Typ", "Elfen")); + CuAssertTrue(tc, cr_find_string(&strm, ";wahrerTyp", "Menschen")); + mstream_done(&strm); + mstream_init(&strm); + cr_output_unit(&strm, f2, u, seen_unit); + CuAssertTrue(tc, cr_find_string(&strm, ";Typ", "Elfen")); + CuAssertTrue(tc, cr_find_string(&strm, ";wahrerTyp", NULL)); + mstream_done(&strm); + + /* when we use racename, nobody can tell it's not the real deal */ + u->irace = NULL; + set_racename(&u->attribs, "Zwerge"); + mstream_init(&strm); + cr_output_unit(&strm, f1, u, seen_unit); + CuAssertTrue(tc, cr_find_string(&strm, ";Typ", "Zwerge")); + CuAssertTrue(tc, cr_find_string(&strm, ";wahrerTyp", NULL)); + mstream_done(&strm); + mstream_init(&strm); + cr_output_unit(&strm, f2, u, seen_unit); + CuAssertTrue(tc, cr_find_string(&strm, ";Typ", "Zwerge")); + CuAssertTrue(tc, cr_find_string(&strm, ";wahrerTyp", NULL)); + mstream_done(&strm); + + test_teardown(); +} + static void test_cr_factionstealth(CuTest *tc) { stream strm; faction *f1, *f2; @@ -326,6 +418,7 @@ CuSuite *get_creport_suite(void) SUITE_ADD_TEST(suite, test_cr_unit); SUITE_ADD_TEST(suite, test_cr_resources); SUITE_ADD_TEST(suite, test_cr_mallorn); + SUITE_ADD_TEST(suite, test_cr_hiderace); SUITE_ADD_TEST(suite, test_cr_factionstealth); return suite; } diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 7c46ab798..c17f4662c 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -279,12 +279,10 @@ unit *addplayer(region * r, faction * f) u->hp = unit_max_hp(u) * u->number; fset(u, UFL_ISNEW); if (f->race == get_race(RC_DAEMON)) { - race_t urc; const race *rc; - do { - urc = (race_t)(rng_int() % MAXRACES); - rc = get_race(urc); - } while (rc == NULL || urc == RC_DAEMON || !playerrace(rc)); + int urc = (race_t)(rng_int() % MAX_START_RACE); + if (urc >= RC_DAEMON) ++urc; + rc = get_race(urc); u->irace = rc; } f->lastorders = turn; diff --git a/src/kernel/race.c b/src/kernel/race.c index 95239bd3f..fdcd5e233 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -48,16 +48,14 @@ int num_races = 0; static int rc_changes = 1; const char *racenames[MAXRACES] = { - "dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect", - "halfling", "cat", "aquarian", "orc", "snotling", "undead", NULL, + "dwarf", "elf", "goblin", "human", "troll", "demon", "insect", + "halfling", "cat", "aquarian", "orc", "snotling", "undead", "youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid", - NULL, NULL, "irongolem", "stonegolem", "shadowdemon", + "irongolem", "stonegolem", "shadowdemon", "shadowmaster", "mountainguard", "alp", "toad", "braineater", "peasant", - "wolf", NULL, NULL, NULL, NULL, "songdragon", NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, "seaserpent", - "shadowknight", NULL, "skeleton", "skeletonlord", "zombie", - "juju", "ghoul", "ghast", NULL, NULL, "template", + "wolf", "songdragon", "seaserpent", + "shadowknight", "skeleton", "skeletonlord", "zombie", + "juju", "ghoul", "ghast", "template", "clone" }; diff --git a/src/kernel/race.h b/src/kernel/race.h index bce12912d..663f33c16 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -35,7 +35,7 @@ extern "C" { typedef enum { RC_DWARF, /* 0 - Zwerg */ RC_ELF, - RC_GOBLIN = 3, + RC_GOBLIN, RC_HUMAN, RC_TROLL, RC_DAEMON, @@ -44,17 +44,19 @@ extern "C" { RC_CAT, RC_AQUARIAN, RC_ORC, + /* last of the addplayer races */ + RC_SNOTLING, RC_UNDEAD, - RC_FIREDRAGON = 15, + RC_FIREDRAGON, RC_DRAGON, RC_WYRM, RC_TREEMAN, RC_BIRTHDAYDRAGON, RC_DRACOID, - RC_IRONGOLEM = 23, + RC_IRONGOLEM, RC_STONEGOLEM, RC_SHADOW, RC_SHADOWLORD, @@ -63,25 +65,27 @@ extern "C" { RC_TOAD, RC_HIRNTOETER, RC_PEASANT, - RC_WOLF = 32, + RC_WOLF, - RC_SONGDRAGON = 37, + RC_SONGDRAGON, - RC_SEASERPENT = 51, + RC_SEASERPENT, RC_SHADOWKNIGHT, - RC_SKELETON = 54, + RC_SKELETON, RC_SKELETON_LORD, RC_ZOMBIE, RC_ZOMBIE_LORD, RC_GHOUL, RC_GHOUL_LORD, - RC_TEMPLATE = 62, + RC_TEMPLATE, RC_CLONE, MAXRACES, NORACE = -1 } race_t; +#define MAX_START_RACE RC_ORC + extern int num_races; extern const char *racenames[MAXRACES]; @@ -241,6 +245,7 @@ extern "C" { #define playerrace(rc) ((rc)->flags & RCF_PLAYABLE) #define dragonrace(rc) ((rc)->flags & RCF_DRAGON) #define humanoidrace(rc) (((rc)->flags & RCF_UNDEAD) || (rc)==get_race(RC_DRACOID) || playerrace(rc)) +#define undeadrace(rc) (((rc)->flags & RCF_UNDEAD) || (rc)==get_race(RC_DRACOID)) #define illusionaryrace(rc) ((rc)->flags & RCF_ILLUSIONARY) bool allowed_dragon(const struct region *src, diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c index dea37345b..2328997c3 100644 --- a/src/spells/combatspells.c +++ b/src/spells/combatspells.c @@ -1399,7 +1399,7 @@ static int heal_fighters(selist * fgs, int *power, bool heal_monsters) continue; /* wir heilen erstmal keine Monster */ - if (heal_monsters || playerrace(u_race(df->unit))) { + if (heal_monsters || !undeadrace(u_race(df->unit))) { int n, hp = df->unit->hp / df->unit->number; int rest = df->unit->hp % df->unit->number;