forked from github/server
moving monsters to eressea
This commit is contained in:
parent
8baf1aff88
commit
9ee6fc250c
17 changed files with 1184 additions and 1204 deletions
|
@ -306,6 +306,26 @@
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\monsters.c"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\spells\regioncurse.c"
|
RelativePath=".\src\spells\regioncurse.c"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
#include <kernel/types.h>
|
||||||
#include "spells/shipcurse.h"
|
#include "spells/shipcurse.h"
|
||||||
|
|
||||||
#include <kernel/ship.h>
|
#include <kernel/ship.h>
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
|
#include <kernel/faction.h>
|
||||||
|
|
||||||
#include <tolua.h>
|
#include <tolua.h>
|
||||||
|
|
||||||
|
@ -19,6 +20,37 @@ tolua_levitate_ship(lua_State * L)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern void spawn_undead(void);
|
||||||
|
extern void spawn_dragons(void);
|
||||||
|
extern void plan_monsters(struct faction * f);
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
tolua_planmonsters(lua_State * L)
|
||||||
|
{
|
||||||
|
faction * f = (faction *)tolua_tousertype(L, 1, get_monsters());
|
||||||
|
if (f) {
|
||||||
|
plan_monsters(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tolua_spawn_dragons(lua_State * L)
|
||||||
|
{
|
||||||
|
spawn_dragons();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tolua_spawn_undead(lua_State * L)
|
||||||
|
{
|
||||||
|
spawn_undead();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
bind_eressea(struct lua_State * L)
|
bind_eressea(struct lua_State * L)
|
||||||
{
|
{
|
||||||
|
@ -26,6 +58,9 @@ bind_eressea(struct lua_State * L)
|
||||||
tolua_beginmodule(L, NULL);
|
tolua_beginmodule(L, NULL);
|
||||||
{
|
{
|
||||||
tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship);
|
tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship);
|
||||||
|
tolua_function(L, TOLUA_CAST "plan_monsters", tolua_planmonsters);
|
||||||
|
tolua_function(L, TOLUA_CAST "spawn_undead", tolua_spawn_undead);
|
||||||
|
tolua_function(L, TOLUA_CAST "spawn_dragons", tolua_spawn_dragons);
|
||||||
}
|
}
|
||||||
tolua_endmodule(L);
|
tolua_endmodule(L);
|
||||||
}
|
}
|
||||||
|
|
1003
src/eressea/src/monsters.c
Normal file
1003
src/eressea/src/monsters.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -12,3 +12,4 @@
|
||||||
|
|
||||||
#include "main.c"
|
#include "main.c"
|
||||||
#include "bindings.c"
|
#include "bindings.c"
|
||||||
|
#include "monsters.c"
|
||||||
|
|
|
@ -222,49 +222,6 @@ tolua_message_region(lua_State * L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
free_script(attrib * a)
|
|
||||||
{
|
|
||||||
lua_State * L = (lua_State *)global.vm_state;
|
|
||||||
if (a->data.i>0) {
|
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, a->data.i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attrib_type at_script = {
|
|
||||||
"script",
|
|
||||||
NULL, free_script, NULL,
|
|
||||||
NULL, NULL, ATF_UNIQUE
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
call_script(lua_State * L, struct unit * u)
|
|
||||||
{
|
|
||||||
const attrib * a = a_findc(u->attribs, &at_script);
|
|
||||||
if (a==NULL) a = a_findc(u->race->attribs, &at_script);
|
|
||||||
if (a!=NULL && a->data.i>0) {
|
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i);
|
|
||||||
if (lua_pcall(L, 1, 0, 0)!=0) {
|
|
||||||
const char* error = lua_tostring(L, -1);
|
|
||||||
log_error(("call_script (%s): %s", unitname(u), error));
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
setscript(lua_State * L, struct attrib ** ap)
|
|
||||||
{
|
|
||||||
attrib * a = a_find(*ap, &at_script);
|
|
||||||
if (a == NULL) {
|
|
||||||
a = a_add(ap, a_new(&at_script));
|
|
||||||
} else if (a->data.i>0) {
|
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, a->data.i);
|
|
||||||
}
|
|
||||||
a->data.i = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tolua_update_guards(lua_State * L)
|
tolua_update_guards(lua_State * L)
|
||||||
{
|
{
|
||||||
|
@ -480,46 +437,6 @@ tolua_levitate_ship(lua_State * L)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int
|
|
||||||
tolua_set_unitscript(lua_State * L)
|
|
||||||
{
|
|
||||||
struct unit * u = (struct unit *)tolua_tousertype(L, 1, 0);
|
|
||||||
if (u) {
|
|
||||||
lua_pushvalue(L, 2);
|
|
||||||
setscript(L, &u->attribs);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
tolua_set_racescript(lua_State * L)
|
|
||||||
{
|
|
||||||
const char * rcname = tolua_tostring(L, 1, 0);
|
|
||||||
race * rc = rc_find(rcname);
|
|
||||||
|
|
||||||
if (rc!=NULL) {
|
|
||||||
lua_pushvalue(L, 2);
|
|
||||||
setscript(L, &rc->attribs);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
tolua_spawn_dragons(lua_State * L)
|
|
||||||
{
|
|
||||||
spawn_dragons();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
tolua_spawn_undead(lua_State * L)
|
|
||||||
{
|
|
||||||
spawn_undead();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tolua_spawn_braineaters(lua_State * L)
|
tolua_spawn_braineaters(lua_State * L)
|
||||||
{
|
{
|
||||||
|
@ -528,22 +445,6 @@ tolua_spawn_braineaters(lua_State * L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
tolua_planmonsters(lua_State * L)
|
|
||||||
{
|
|
||||||
faction * f = get_monsters();
|
|
||||||
|
|
||||||
if (f!=NULL) {
|
|
||||||
unit * u;
|
|
||||||
plan_monsters();
|
|
||||||
for (u=f->units;u;u=u->nextF) {
|
|
||||||
call_script(L, u);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tolua_init_reports(lua_State* L)
|
tolua_init_reports(lua_State* L)
|
||||||
{
|
{
|
||||||
|
@ -1185,13 +1086,7 @@ tolua_eressea_open(lua_State* L)
|
||||||
tolua_function(L, TOLUA_CAST "message_region", tolua_message_region);
|
tolua_function(L, TOLUA_CAST "message_region", tolua_message_region);
|
||||||
|
|
||||||
/* scripted monsters */
|
/* scripted monsters */
|
||||||
tolua_function(L, TOLUA_CAST "plan_monsters", tolua_planmonsters);
|
|
||||||
tolua_function(L, TOLUA_CAST "spawn_braineaters", tolua_spawn_braineaters);
|
tolua_function(L, TOLUA_CAST "spawn_braineaters", tolua_spawn_braineaters);
|
||||||
tolua_function(L, TOLUA_CAST "spawn_undead", tolua_spawn_undead);
|
|
||||||
tolua_function(L, TOLUA_CAST "spawn_dragons", tolua_spawn_dragons);
|
|
||||||
|
|
||||||
tolua_function(L, TOLUA_CAST "set_race_brain", tolua_set_racescript);
|
|
||||||
tolua_function(L, TOLUA_CAST "set_unit_brain", tolua_set_unitscript);
|
|
||||||
|
|
||||||
#ifdef TODO_FOSS
|
#ifdef TODO_FOSS
|
||||||
/* spells and stuff */
|
/* spells and stuff */
|
||||||
|
|
|
@ -4069,7 +4069,7 @@ init_processor(void)
|
||||||
p+=10;
|
p+=10;
|
||||||
add_proc_global(p, &encounters, "Zufallsbegegnungen");
|
add_proc_global(p, &encounters, "Zufallsbegegnungen");
|
||||||
p+=10;
|
p+=10;
|
||||||
add_proc_unit(p, &monsters_kill_peasants, "Monster fressen und vertreiben Bauern");
|
add_proc_unit(p, &monster_kills_peasants, "Monster fressen und vertreiben Bauern");
|
||||||
|
|
||||||
p+=10;
|
p+=10;
|
||||||
add_proc_global(p, &randomevents, "Zufallsereignisse");
|
add_proc_global(p, &randomevents, "Zufallsereignisse");
|
||||||
|
|
|
@ -73,526 +73,13 @@
|
||||||
|
|
||||||
#define MAXILLUSION_TEXTS 3
|
#define MAXILLUSION_TEXTS 3
|
||||||
|
|
||||||
static void
|
boolean
|
||||||
reduce_weight(unit * u)
|
monster_is_waiting(const unit * u)
|
||||||
{
|
|
||||||
int capacity, weight = 0;
|
|
||||||
item ** itmp = &u->items;
|
|
||||||
int horses = get_resource(u, oldresourcetype[R_HORSE]);
|
|
||||||
|
|
||||||
if (horses > 0) {
|
|
||||||
horses = MIN(horses, (u->number*2));
|
|
||||||
change_resource(u, oldresourcetype[R_HORSE], - horses);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 0. ditch any vehicles */
|
|
||||||
while (*itmp!=NULL) {
|
|
||||||
item * itm = *itmp;
|
|
||||||
const item_type * itype = itm->type;
|
|
||||||
weight += itm->number*itype->weight;
|
|
||||||
if (itype->flags & ITF_VEHICLE) {
|
|
||||||
give_item(itm->number, itm->type, u, NULL, NULL);
|
|
||||||
}
|
|
||||||
if (*itmp==itm) itmp=&itm->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
capacity = walkingcapacity(u);
|
|
||||||
|
|
||||||
/* 1. get rid of anything that isn't silver or really lightweight or helpful in combat */
|
|
||||||
for (itmp = &u->items;*itmp && capacity>0;) {
|
|
||||||
item * itm = *itmp;
|
|
||||||
const item_type * itype = itm->type;
|
|
||||||
weight += itm->number*itype->weight;
|
|
||||||
if (weight>capacity) {
|
|
||||||
if (itype->weight>=10 && itype->rtype->wtype==0 && itype->rtype->atype==0) {
|
|
||||||
if (itype->capacity < itype->weight) {
|
|
||||||
int reduce = MIN(itm->number, -((capacity-weight)/itype->weight));
|
|
||||||
give_item(reduce, itm->type, u, NULL, NULL);
|
|
||||||
weight -= reduce * itype->weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (*itmp==itm) itmp=&itm->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (itmp = &u->items;*itmp && weight>capacity;) {
|
|
||||||
item * itm = *itmp;
|
|
||||||
const item_type * itype = itm->type;
|
|
||||||
weight += itm->number*itype->weight;
|
|
||||||
if (itype->capacity < itype->weight) {
|
|
||||||
int reduce = MIN(itm->number, -((capacity-weight)/itype->weight));
|
|
||||||
give_item(reduce, itm->type, u, NULL, NULL);
|
|
||||||
weight -= reduce * itype->weight;
|
|
||||||
}
|
|
||||||
if (*itmp==itm) itmp=&itm->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean
|
|
||||||
is_waiting(const unit * u)
|
|
||||||
{
|
{
|
||||||
if (fval(u, UFL_ISNEW|UFL_MOVED)) return true;
|
if (fval(u, UFL_ISNEW|UFL_MOVED)) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static order *
|
|
||||||
monster_attack(unit * u, const unit * target)
|
|
||||||
{
|
|
||||||
if (u->region!=target->region) return NULL;
|
|
||||||
if (u->faction==target->faction) return NULL;
|
|
||||||
if (!cansee(u->faction, u->region, target, 0)) return NULL;
|
|
||||||
if (is_waiting(u)) return NULL;
|
|
||||||
|
|
||||||
return create_order(K_ATTACK, u->faction->locale, "%i", target->no);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static order *
|
|
||||||
get_money_for_dragon(region * r, unit * u, int wanted)
|
|
||||||
{
|
|
||||||
unit *u2;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
/* attackiere bewachende einheiten */
|
|
||||||
for (u2 = r->units; u2; u2 = u2->next) {
|
|
||||||
if (u2 != u && is_guard(u2, GUARD_TAX)) {
|
|
||||||
order * ord = monster_attack(u, u2);
|
|
||||||
if (ord) addlist(&u->orders, ord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* falls genug geld in der region ist, treiben wir steuern ein. */
|
|
||||||
if (rmoney(r) >= wanted) {
|
|
||||||
/* 5% chance, dass der drache aus einer laune raus attackiert */
|
|
||||||
if (chance(1.0-u->race->aggression)) {
|
|
||||||
return create_order(K_TAX, default_locale, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* falls der drache launisch ist, oder das regionssilber knapp, greift er alle an */
|
|
||||||
n = 0;
|
|
||||||
for (u2 = r->units; u2; u2 = u2->next) {
|
|
||||||
if (u2->faction != u->faction && cansee(u->faction, r, u2, 0)) {
|
|
||||||
int m = get_money(u2);
|
|
||||||
if (m==0 || is_guard(u2, GUARD_TAX)) continue;
|
|
||||||
else {
|
|
||||||
order * ord = monster_attack(u, u2);
|
|
||||||
if (ord) {
|
|
||||||
addlist(&u->orders, ord);
|
|
||||||
n += m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* falls die einnahmen erreicht werden, bleibt das monster noch eine
|
|
||||||
* runde hier. */
|
|
||||||
if (n + rmoney(r) >= wanted) {
|
|
||||||
return create_order(K_TAX, default_locale, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* wenn wir NULL zurückliefern, macht der drache was anderes, z.b. weggehen */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
all_money(region * r, faction * f)
|
|
||||||
{
|
|
||||||
unit *u;
|
|
||||||
int m;
|
|
||||||
|
|
||||||
m = rmoney(r);
|
|
||||||
for (u = r->units; u; u = u->next) {
|
|
||||||
if (f!=u->faction) {
|
|
||||||
m += get_money(u);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static direction_t
|
|
||||||
richest_neighbour(region * r, faction * f, int absolut)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* m - maximum an Geld, d - Richtung, i - index, t = Geld hier */
|
|
||||||
|
|
||||||
double m;
|
|
||||||
double t;
|
|
||||||
direction_t d = NODIRECTION, i;
|
|
||||||
|
|
||||||
if (absolut == 1 || rpeasants(r) == 0) {
|
|
||||||
m = (double) all_money(r, f);
|
|
||||||
} else {
|
|
||||||
m = (double) all_money(r, f) / (double) rpeasants(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* finde die region mit dem meisten geld */
|
|
||||||
|
|
||||||
for (i = 0; i != MAXDIRECTIONS; i++) {
|
|
||||||
region * rn = rconnect(r, i);
|
|
||||||
if (rn!=NULL && fval(rn->terrain, LAND_REGION)) {
|
|
||||||
if (absolut == 1 || rpeasants(rn) == 0) {
|
|
||||||
t = (double) all_money(rn, f);
|
|
||||||
} else {
|
|
||||||
t = (double) all_money(rn, f) / (double) rpeasants(rn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t > m) {
|
|
||||||
m = t;
|
|
||||||
d = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean
|
|
||||||
room_for_race_in_region(region *r, const race * rc)
|
|
||||||
{
|
|
||||||
unit *u;
|
|
||||||
int c = 0;
|
|
||||||
|
|
||||||
for(u=r->units;u;u=u->next) {
|
|
||||||
if(u->race == rc) c += u->number;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(c > (rc->splitsize*2))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static direction_t
|
|
||||||
random_neighbour(region * r, unit *u)
|
|
||||||
{
|
|
||||||
direction_t i;
|
|
||||||
region *rc;
|
|
||||||
int rr, c = 0, c2 = 0;
|
|
||||||
|
|
||||||
/* Nachsehen, wieviele Regionen in Frage kommen */
|
|
||||||
|
|
||||||
for (i = 0; i != MAXDIRECTIONS; i++) {
|
|
||||||
rc = rconnect(r, i);
|
|
||||||
if (rc && can_survive(u, rc)) {
|
|
||||||
if(room_for_race_in_region(rc, u->race)) {
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
c2++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == 0) {
|
|
||||||
if(c2 == 0) {
|
|
||||||
return NODIRECTION;
|
|
||||||
} else {
|
|
||||||
c = c2;
|
|
||||||
c2 = 0; /* c2 == 0 -> room_for_race nicht beachten */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Zufällig eine auswählen */
|
|
||||||
|
|
||||||
rr = rng_int() % c;
|
|
||||||
|
|
||||||
/* Durchzählen */
|
|
||||||
|
|
||||||
c = -1;
|
|
||||||
for (i = 0; i != MAXDIRECTIONS; i++) {
|
|
||||||
rc = rconnect(r, i);
|
|
||||||
if (rc && can_survive(u, rc)) {
|
|
||||||
if(c2 == 0) {
|
|
||||||
c++;
|
|
||||||
} else if(room_for_race_in_region(rc, u->race)) {
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
if (c == rr) return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(1 == 0); /* Bis hierhin sollte er niemals kommen. */
|
|
||||||
return NODIRECTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
static direction_t
|
|
||||||
treeman_neighbour(region * r)
|
|
||||||
{
|
|
||||||
direction_t i;
|
|
||||||
int rr;
|
|
||||||
int c = 0;
|
|
||||||
|
|
||||||
/* Nachsehen, wieviele Regionen in Frage kommen */
|
|
||||||
|
|
||||||
for (i = 0; i != MAXDIRECTIONS; i++) {
|
|
||||||
if (rconnect(r, i)
|
|
||||||
&& rterrain(rconnect(r, i)) != T_OCEAN
|
|
||||||
&& rterrain(rconnect(r, i)) != T_GLACIER
|
|
||||||
&& rterrain(rconnect(r, i)) != T_DESERT) {
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == 0) {
|
|
||||||
return NODIRECTION;
|
|
||||||
}
|
|
||||||
/* Zufällig eine auswählen */
|
|
||||||
|
|
||||||
rr = rng_int() % c;
|
|
||||||
|
|
||||||
/* Durchzählen */
|
|
||||||
|
|
||||||
c = -1;
|
|
||||||
for (i = 0; i != MAXDIRECTIONS; i++) {
|
|
||||||
if (rconnect(r, i)
|
|
||||||
&& rterrain(rconnect(r, i)) != T_OCEAN
|
|
||||||
&& rterrain(rconnect(r, i)) != T_GLACIER
|
|
||||||
&& rterrain(rconnect(r, i)) != T_DESERT) {
|
|
||||||
c++;
|
|
||||||
if (c == rr) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(1 == 0); /* Bis hierhin sollte er niemals kommen. */
|
|
||||||
return NODIRECTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
static order *
|
|
||||||
monster_move(region * r, unit * u)
|
|
||||||
{
|
|
||||||
direction_t d = NODIRECTION;
|
|
||||||
|
|
||||||
if (is_waiting(u)) return NULL;
|
|
||||||
switch(old_race(u->race)) {
|
|
||||||
case RC_FIREDRAGON:
|
|
||||||
case RC_DRAGON:
|
|
||||||
case RC_WYRM:
|
|
||||||
d = richest_neighbour(r, u->faction, 1);
|
|
||||||
break;
|
|
||||||
case RC_TREEMAN:
|
|
||||||
d = treeman_neighbour(r);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
d = random_neighbour(r,u);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* falls kein geld gefunden wird, zufaellig verreisen, aber nicht in
|
|
||||||
* den ozean */
|
|
||||||
|
|
||||||
if (d == NODIRECTION)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
reduce_weight(u);
|
|
||||||
return create_order(K_MOVE, u->faction->locale, "%s", LOC(u->faction->locale, directions[d]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wir machen das mal autoconf-style: */
|
|
||||||
#ifndef HAVE_DRAND48
|
|
||||||
#define drand48() (((double)rng_int()) / RAND_MAX)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
|
||||||
dragon_affinity_value(region *r, unit *u)
|
|
||||||
{
|
|
||||||
int m = all_money(r, u->faction);
|
|
||||||
|
|
||||||
if(u->race == new_race[RC_FIREDRAGON]) {
|
|
||||||
return (int)(normalvariate(m,m/2));
|
|
||||||
} else {
|
|
||||||
return (int)(normalvariate(m,m/4));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static attrib *
|
|
||||||
set_new_dragon_target(unit * u, region * r, int range)
|
|
||||||
{
|
|
||||||
int max_affinity = 0;
|
|
||||||
region *max_region = NULL;
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
region_list * rptr, * rlist = regions_in_range(r, range, allowed_dragon);
|
|
||||||
for (rptr=rlist;rptr;rptr=rptr->next) {
|
|
||||||
region * r2 = rptr->data;
|
|
||||||
int affinity = dragon_affinity_value(r2, u);
|
|
||||||
if (affinity > max_affinity) {
|
|
||||||
max_affinity = affinity;
|
|
||||||
max_region = r2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free_regionlist(rlist);
|
|
||||||
#else
|
|
||||||
int tx, ty;
|
|
||||||
for (tx = r->x - range; tx < r->x + range; tx++) {
|
|
||||||
for (ty = r->y - range; ty < r->y + range; ty++) {
|
|
||||||
region * r2;
|
|
||||||
int x = tx, y = ty;
|
|
||||||
pnormalize(&x, &y, r->planep);
|
|
||||||
r2 = findregion(x, y);
|
|
||||||
if (r2!=NULL) {
|
|
||||||
int affinity = dragon_affinity_value(r2, u);
|
|
||||||
if (affinity > max_affinity) {
|
|
||||||
if (koor_distance (r->x, r->y, x, y) <= range && path_exists(r, r2, range, allowed_dragon))
|
|
||||||
{
|
|
||||||
max_affinity = affinity;
|
|
||||||
max_region = r2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (max_region && max_region != r) {
|
|
||||||
attrib * a = a_find(u->attribs, &at_targetregion);
|
|
||||||
if (!a) {
|
|
||||||
a = a_add(&u->attribs, make_targetregion(max_region));
|
|
||||||
} else {
|
|
||||||
a->data.v = max_region;
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static order *
|
|
||||||
make_movement_order(unit * u, const region * target, int moves, boolean (*allowed)(const region *, const region *))
|
|
||||||
{
|
|
||||||
region * r = u->region;
|
|
||||||
region ** plan;
|
|
||||||
int bytes, position = 0;
|
|
||||||
char zOrder[128], * bufp = zOrder;
|
|
||||||
size_t size = sizeof(zOrder) - 1;
|
|
||||||
|
|
||||||
if (is_waiting(u)) return NULL;
|
|
||||||
|
|
||||||
plan = path_find(r, target, DRAGON_RANGE*5, allowed);
|
|
||||||
if (plan==NULL) return NULL;
|
|
||||||
|
|
||||||
bytes = (int)strlcpy(bufp, (const char *)LOC(u->faction->locale, keywords[K_MOVE]), size);
|
|
||||||
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
|
||||||
|
|
||||||
while (position!=moves && plan[position+1]) {
|
|
||||||
region * prev = plan[position];
|
|
||||||
region * next = plan[++position];
|
|
||||||
direction_t dir = reldirection(prev, next);
|
|
||||||
assert(dir!=NODIRECTION && dir!=D_SPECIAL);
|
|
||||||
if (size>1) {
|
|
||||||
*bufp++ = ' ';
|
|
||||||
--size;
|
|
||||||
}
|
|
||||||
bytes = (int)strlcpy(bufp, (const char *)LOC(u->faction->locale, directions[dir]), size);
|
|
||||||
if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER();
|
|
||||||
}
|
|
||||||
|
|
||||||
*bufp = 0;
|
|
||||||
return parse_order(zOrder, u->faction->locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TODO_ALP
|
|
||||||
static order *
|
|
||||||
monster_seeks_target(region *r, unit *u)
|
|
||||||
{
|
|
||||||
direction_t d;
|
|
||||||
unit *target = NULL;
|
|
||||||
int dist, dist2;
|
|
||||||
direction_t i;
|
|
||||||
region *nr;
|
|
||||||
|
|
||||||
/* Das Monster sucht ein bestimmtes Opfer. Welches, steht
|
|
||||||
* in einer Referenz/attribut
|
|
||||||
* derzeit gibt es nur den alp
|
|
||||||
*/
|
|
||||||
|
|
||||||
switch( old_race(u->race) ) {
|
|
||||||
case RC_ALP:
|
|
||||||
target = alp_target(u);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(!"Seeker-Monster gibt kein Ziel an");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: prüfen, ob target überhaupt noch existiert... */
|
|
||||||
if (!target) {
|
|
||||||
log_error(("Monster '%s' hat kein Ziel!\n", unitname(u)));
|
|
||||||
return NULL; /* this is a bug workaround! remove!! */
|
|
||||||
}
|
|
||||||
|
|
||||||
if(r == target->region ) { /* Wir haben ihn! */
|
|
||||||
if (u->race == new_race[RC_ALP]) {
|
|
||||||
alp_findet_opfer(u, r);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(!"Seeker-Monster hat keine Aktion fuer Ziel");
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Simpler Ansatz: Nachbarregion mit gerinster Distanz suchen.
|
|
||||||
* Sinnvoll momentan nur bei Monstern, die sich nicht um das
|
|
||||||
* Terrain kümmern. Nebelwände & Co machen derzeit auch nix...
|
|
||||||
*/
|
|
||||||
dist2 = distance(r, target->region);
|
|
||||||
d = NODIRECTION;
|
|
||||||
for( i = 0; i < MAXDIRECTIONS; i++ ) {
|
|
||||||
nr = rconnect(r, i);
|
|
||||||
assert(nr);
|
|
||||||
dist = distance(nr, target->region);
|
|
||||||
if( dist < dist2 ) {
|
|
||||||
dist2 = dist;
|
|
||||||
d = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(d != NODIRECTION );
|
|
||||||
|
|
||||||
return create_order(K_MOVE, u->faction->locale, "%s", LOC(u->faction->locale, directions[d]));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
unit *
|
|
||||||
random_unit(const region * r)
|
|
||||||
{
|
|
||||||
int c = 0;
|
|
||||||
int n;
|
|
||||||
unit *u;
|
|
||||||
|
|
||||||
for (u = r->units; u; u = u->next) {
|
|
||||||
if (u->race != new_race[RC_SPELL]) {
|
|
||||||
c += u->number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
n = rng_int() % c;
|
|
||||||
c = 0;
|
|
||||||
u = r->units;
|
|
||||||
|
|
||||||
while (u && c < n) {
|
|
||||||
if (u->race != new_race[RC_SPELL]) {
|
|
||||||
c += u->number;
|
|
||||||
}
|
|
||||||
u = u->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return u;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
monster_attacks(unit * u)
|
|
||||||
{
|
|
||||||
region * r = u->region;
|
|
||||||
unit * u2;
|
|
||||||
|
|
||||||
for (u2=r->units;u2;u2=u2->next) {
|
|
||||||
if (u2->faction!=u->faction && chance(0.75)) {
|
|
||||||
order * ord = monster_attack(u, u2);
|
|
||||||
if (ord) addlist(&u->orders, ord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
eaten_by_monster(unit * u)
|
eaten_by_monster(unit * u)
|
||||||
{
|
{
|
||||||
|
@ -726,60 +213,10 @@ scared_by_monster(unit * u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
|
||||||
random_growl(void)
|
|
||||||
{
|
|
||||||
switch(rng_int()%5) {
|
|
||||||
case 0:
|
|
||||||
return "Groammm";
|
|
||||||
case 1:
|
|
||||||
return "Roaaarrrr";
|
|
||||||
case 2:
|
|
||||||
return "Chhhhhhhhhh";
|
|
||||||
case 3:
|
|
||||||
return "Tschrrrkk";
|
|
||||||
case 4:
|
|
||||||
return "Schhhh";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
extern struct attrib_type at_direction;
|
|
||||||
|
|
||||||
static order *
|
|
||||||
monster_learn(unit *u)
|
|
||||||
{
|
|
||||||
int c = 0;
|
|
||||||
int n;
|
|
||||||
skill * sv;
|
|
||||||
const struct locale * lang = u->faction->locale;
|
|
||||||
|
|
||||||
/* Monster lernt ein zufälliges Talent aus allen, in denen es schon
|
|
||||||
* Lerntage hat. */
|
|
||||||
|
|
||||||
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
|
|
||||||
if (sv->level>0) ++c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(c == 0) return NULL;
|
|
||||||
|
|
||||||
n = rng_int()%c + 1;
|
|
||||||
c = 0;
|
|
||||||
|
|
||||||
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
|
|
||||||
if (sv->level>0) {
|
|
||||||
if (++c == n) {
|
|
||||||
return create_order(K_STUDY, lang, "'%s'", skillname(sv->id, lang));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
monsters_kill_peasants(unit * u)
|
monster_kills_peasants(unit * u)
|
||||||
{
|
{
|
||||||
if (!is_waiting(u)) {
|
if (!monster_is_waiting(u)) {
|
||||||
if (u->race->flags & RCF_SCAREPEASANTS) {
|
if (u->race->flags & RCF_SCAREPEASANTS) {
|
||||||
scared_by_monster(u);
|
scared_by_monster(u);
|
||||||
}
|
}
|
||||||
|
@ -791,406 +228,3 @@ monsters_kill_peasants(unit * u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean
|
|
||||||
check_overpopulated(unit *u)
|
|
||||||
{
|
|
||||||
unit *u2;
|
|
||||||
int c = 0;
|
|
||||||
|
|
||||||
for(u2 = u->region->units; u2; u2 = u2->next) {
|
|
||||||
if(u2->race == u->race && u != u2) c += u2->number;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(c > u->race->splitsize * 2) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
recruit_dracoids(unit * dragon, int size)
|
|
||||||
{
|
|
||||||
faction * f = dragon->faction;
|
|
||||||
region * r = dragon->region;
|
|
||||||
const struct item * weapon = NULL;
|
|
||||||
order * new_order = NULL;
|
|
||||||
unit *un = createunit(r, f, size, new_race[RC_DRACOID]);
|
|
||||||
|
|
||||||
fset(un, UFL_ISNEW|UFL_MOVED);
|
|
||||||
|
|
||||||
name_unit(un);
|
|
||||||
change_money(dragon, -un->number * 50);
|
|
||||||
equip_unit(un, get_equipment("recruited_dracoid"));
|
|
||||||
|
|
||||||
setstatus(un, ST_FIGHT);
|
|
||||||
for (weapon=un->items;weapon;weapon=weapon->next) {
|
|
||||||
const weapon_type * wtype = weapon->type->rtype->wtype;
|
|
||||||
if (wtype && (wtype->flags & WTF_MISSILE)) {
|
|
||||||
setstatus(un, ST_BEHIND);
|
|
||||||
}
|
|
||||||
new_order = create_order(K_STUDY, f->locale, "'%s'",
|
|
||||||
skillname(weapon->type->rtype->wtype->skill, f->locale));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_order!=NULL) {
|
|
||||||
addlist(&un->orders, new_order);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static order *
|
|
||||||
plan_dragon(unit * u)
|
|
||||||
{
|
|
||||||
attrib * ta = a_find(u->attribs, &at_targetregion);
|
|
||||||
region * r = u->region;
|
|
||||||
region * tr = NULL;
|
|
||||||
boolean move = false;
|
|
||||||
order * long_order = NULL;
|
|
||||||
|
|
||||||
reduce_weight(u);
|
|
||||||
|
|
||||||
if (ta==NULL) {
|
|
||||||
move |= (r->land==0 || r->land->peasants==0); /* when no peasants, move */
|
|
||||||
move |= (r->land==0 || r->land->money==0); /* when no money, move */
|
|
||||||
}
|
|
||||||
move |= chance(0.04); /* 4% chance to change your mind */
|
|
||||||
|
|
||||||
if (u->race==new_race[RC_WYRM] && !move) {
|
|
||||||
unit * u2;
|
|
||||||
for (u2=r->units;u2;u2=u2->next) {
|
|
||||||
/* wyrme sind einzelgänger */
|
|
||||||
if (u2==u) {
|
|
||||||
/* we do not make room for newcomers, so we don't need to look at them */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (u2!=u && u2->race==u->race && chance(0.5)) {
|
|
||||||
move = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (move) {
|
|
||||||
/* dragon gets bored and looks for a different place to go */
|
|
||||||
ta = set_new_dragon_target(u, u->region, DRAGON_RANGE);
|
|
||||||
}
|
|
||||||
else ta = a_find(u->attribs, &at_targetregion);
|
|
||||||
if (ta!=NULL) {
|
|
||||||
tr = (region *) ta->data.v;
|
|
||||||
if (tr==NULL || !path_exists(u->region, tr, DRAGON_RANGE, allowed_dragon)) {
|
|
||||||
ta = set_new_dragon_target(u, u->region, DRAGON_RANGE);
|
|
||||||
if (ta) tr = findregion(ta->data.sa[0], ta->data.sa[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tr!=NULL) {
|
|
||||||
assert(long_order==NULL);
|
|
||||||
switch(old_race(u->race)) {
|
|
||||||
case RC_FIREDRAGON:
|
|
||||||
long_order = make_movement_order(u, tr, 4, allowed_dragon);
|
|
||||||
break;
|
|
||||||
case RC_DRAGON:
|
|
||||||
long_order = make_movement_order(u, tr, 3, allowed_dragon);
|
|
||||||
break;
|
|
||||||
case RC_WYRM:
|
|
||||||
long_order = make_movement_order(u, tr, 1, allowed_dragon);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (rng_int()%100 < 15) {
|
|
||||||
const struct locale * lang = u->faction->locale;
|
|
||||||
/* do a growl */
|
|
||||||
if (rname(tr, lang)) {
|
|
||||||
addlist(&u->orders, create_order(K_MAIL, lang, "%s '%s... %s %s %s'",
|
|
||||||
LOC(lang, parameters[P_REGION]), random_growl(),
|
|
||||||
u->number==1?"Ich rieche":"Wir riechen",
|
|
||||||
"etwas in", rname(tr, u->faction->locale)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* we have no target. do we like it here, then? */
|
|
||||||
long_order = get_money_for_dragon(u->region, u, income(u));
|
|
||||||
if (long_order==NULL) {
|
|
||||||
/* money is gone, need a new target */
|
|
||||||
set_new_dragon_target(u, u->region, DRAGON_RANGE);
|
|
||||||
}
|
|
||||||
else if (u->race != new_race[RC_FIREDRAGON]) {
|
|
||||||
/* neue dracoiden! */
|
|
||||||
if (r->land && !fval(r->terrain, FORBIDDEN_REGION)) {
|
|
||||||
int ra = 20 + rng_int() % 100;
|
|
||||||
if (get_money(u) > ra * 50 + 100 && rng_int() % 100 < 50) {
|
|
||||||
recruit_dracoids(u, ra);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (long_order==NULL) {
|
|
||||||
skill_t sk = SK_PERCEPTION;
|
|
||||||
/* study perception (or a random useful skill) */
|
|
||||||
while (!skill_enabled[sk] || u->race->bonus[sk]<-5) {
|
|
||||||
sk = (skill_t)(rng_int() % MAXSKILLS);
|
|
||||||
}
|
|
||||||
long_order = create_order(K_STUDY, u->faction->locale, "'%s'",
|
|
||||||
skillname(sk, u->faction->locale));
|
|
||||||
}
|
|
||||||
return long_order;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
plan_monsters(void)
|
|
||||||
{
|
|
||||||
region *r;
|
|
||||||
faction *f = get_monsters();
|
|
||||||
|
|
||||||
if (!f) return;
|
|
||||||
f->lastorders = turn;
|
|
||||||
|
|
||||||
for (r = regions; r; r = r->next) {
|
|
||||||
unit *u;
|
|
||||||
double attack_chance = MONSTERATTACK;
|
|
||||||
boolean attacking = false;
|
|
||||||
|
|
||||||
for (u = r->units; u; u = u->next) {
|
|
||||||
attrib * ta;
|
|
||||||
order * long_order = NULL;
|
|
||||||
|
|
||||||
/* Ab hier nur noch Befehle für NPC-Einheiten. */
|
|
||||||
if (!is_monsters(u->faction)) continue;
|
|
||||||
|
|
||||||
if (attack_chance>0.0) {
|
|
||||||
if (chance(attack_chance)) attacking = true;
|
|
||||||
attack_chance = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (u->status>ST_BEHIND) {
|
|
||||||
setstatus(u, ST_FIGHT);
|
|
||||||
/* all monsters fight */
|
|
||||||
}
|
|
||||||
if (skill_enabled[SK_PERCEPTION]) {
|
|
||||||
/* Monster bekommen jede Runde ein paar Tage Wahrnehmung dazu */
|
|
||||||
/* TODO: this only works for playerrace */
|
|
||||||
produceexp(u, SK_PERCEPTION, u->number);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Befehle müssen jede Runde neu gegeben werden: */
|
|
||||||
free_orders(&u->orders);
|
|
||||||
|
|
||||||
if (attacking) {
|
|
||||||
monster_attacks(u);
|
|
||||||
}
|
|
||||||
/* units with a plan to kill get ATTACK orders: */
|
|
||||||
ta = a_find(u->attribs, &at_hate);
|
|
||||||
if (ta && !is_waiting(u)) {
|
|
||||||
unit * tu = (unit *)ta->data.v;
|
|
||||||
if (tu && tu->region==r) {
|
|
||||||
addlist(&u->orders, create_order(K_ATTACK, u->faction->locale, "%i", tu->no));
|
|
||||||
} else if (tu) {
|
|
||||||
tu = findunitg(ta->data.i, NULL);
|
|
||||||
if (tu!=NULL) {
|
|
||||||
long_order = make_movement_order(u, tu->region, 2, allowed_walk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else a_remove(&u->attribs, ta);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All monsters guard the region: */
|
|
||||||
if (!is_waiting(u) && r->land) {
|
|
||||||
addlist(&u->orders, create_order(K_GUARD, u->faction->locale, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Einheiten mit Bewegungsplan kriegen ein NACH: */
|
|
||||||
if (long_order==NULL) {
|
|
||||||
attrib * ta = a_find(u->attribs, &at_targetregion);
|
|
||||||
if (ta) {
|
|
||||||
if (u->region == (region*)ta->data.v) {
|
|
||||||
a_remove(&u->attribs, ta);
|
|
||||||
}
|
|
||||||
} else if (u->race->flags & RCF_MOVERANDOM) {
|
|
||||||
if (rng_int()%100<MOVECHANCE || check_overpopulated(u)) {
|
|
||||||
long_order = monster_move(r, u);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (long_order==NULL) {
|
|
||||||
/* Einheiten, die Waffenlosen Kampf lernen könnten, lernen es um
|
|
||||||
* zu bewachen: */
|
|
||||||
if (u->race->bonus[SK_WEAPONLESS] != -99) {
|
|
||||||
if (eff_skill(u, SK_WEAPONLESS, u->region) < 1) {
|
|
||||||
long_order = create_order(K_STUDY, f->locale, "'%s'", skillname(SK_WEAPONLESS, f->locale));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (long_order==NULL) {
|
|
||||||
/* Ab hier noch nicht generalisierte Spezialbehandlungen. */
|
|
||||||
|
|
||||||
if (!u->orders) {
|
|
||||||
handle_event(u->attribs, "ai_move", u);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (old_race(u->race)) {
|
|
||||||
case RC_SEASERPENT:
|
|
||||||
long_order = create_order(K_PIRACY, f->locale, NULL);
|
|
||||||
break;
|
|
||||||
#ifdef TODO_ALP
|
|
||||||
case RC_ALP:
|
|
||||||
long_order = monster_seeks_target(r, u);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case RC_FIREDRAGON:
|
|
||||||
case RC_DRAGON:
|
|
||||||
case RC_WYRM:
|
|
||||||
long_order = plan_dragon(u);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (u->race->flags & RCF_LEARN) {
|
|
||||||
long_order = monster_learn(u);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (long_order) {
|
|
||||||
addlist(&u->orders, long_order);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pathfinder_cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
static double
|
|
||||||
chaosfactor(region * r)
|
|
||||||
{
|
|
||||||
attrib * a = a_find(r->attribs, &at_chaoscount);
|
|
||||||
if (!a) return 0;
|
|
||||||
return ((double) a->data.i / 1000.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nrand(int start, int sub)
|
|
||||||
{
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (rng_int() % 100 < start)
|
|
||||||
res++;
|
|
||||||
start -= sub;
|
|
||||||
} while (start > 0);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Drachen und Seeschlangen können entstehen */
|
|
||||||
void
|
|
||||||
spawn_dragons(void)
|
|
||||||
{
|
|
||||||
region * r;
|
|
||||||
faction * monsters = get_monsters();
|
|
||||||
|
|
||||||
for (r = regions; r; r = r->next) {
|
|
||||||
unit * u;
|
|
||||||
|
|
||||||
if (fval(r->terrain, SEA_REGION) && rng_int()%10000 < 1) {
|
|
||||||
u = createunit(r, monsters, 1, new_race[RC_SEASERPENT]);
|
|
||||||
fset(u, UFL_ISNEW|UFL_MOVED);
|
|
||||||
equip_unit(u, get_equipment("monster_seaserpent"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((r->terrain == newterrain(T_GLACIER) || r->terrain == newterrain(T_SWAMP) || r->terrain == newterrain(T_DESERT)) && rng_int() % 10000 < (5 + 100 * chaosfactor(r)))
|
|
||||||
{
|
|
||||||
if (chance(0.80)) {
|
|
||||||
u = createunit(r, monsters, nrand(60, 20) + 1, new_race[RC_FIREDRAGON]);
|
|
||||||
} else {
|
|
||||||
u = createunit(r, monsters, nrand(30, 20) + 1, new_race[RC_DRAGON]);
|
|
||||||
}
|
|
||||||
fset(u, UFL_ISNEW|UFL_MOVED);
|
|
||||||
equip_unit(u, get_equipment("monster_dragon"));
|
|
||||||
|
|
||||||
if (verbosity>=2) {
|
|
||||||
log_printf("%d %s in %s.\n", u->number,
|
|
||||||
LOC(default_locale, rc_name(u->race, u->number!=1)), regionname(r, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
name_unit(u);
|
|
||||||
|
|
||||||
/* add message to the region */
|
|
||||||
ADDMSG(&r->msgs,
|
|
||||||
msg_message("sighting", "region race number", r, u->race, u->number));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Untote können entstehen */
|
|
||||||
void
|
|
||||||
spawn_undead(void)
|
|
||||||
{
|
|
||||||
region * r;
|
|
||||||
faction * monsters = get_monsters();
|
|
||||||
|
|
||||||
for (r = regions; r; r = r->next) {
|
|
||||||
int unburied = deathcount(r);
|
|
||||||
static const curse_type * ctype = NULL;
|
|
||||||
|
|
||||||
if (!ctype) ctype = ct_find("holyground");
|
|
||||||
if (ctype && curse_active(get_curse(r->attribs, ctype))) continue;
|
|
||||||
|
|
||||||
/* Chance 0.1% * chaosfactor */
|
|
||||||
if (r->land && unburied > r->land->peasants / 20 && rng_int() % 10000 < (100 + 100 * chaosfactor(r))) {
|
|
||||||
unit * u;
|
|
||||||
/* es ist sinnfrei, wenn irgendwo im Wald 3er-Einheiten Untote entstehen.
|
|
||||||
* Lieber sammeln lassen, bis sie mindestens 5% der Bevölkerung sind, und
|
|
||||||
* dann erst auferstehen. */
|
|
||||||
int undead = unburied / (rng_int() % 2 + 1);
|
|
||||||
const race * rc = NULL;
|
|
||||||
int i;
|
|
||||||
if (r->age<100) undead = undead * r->age / 100; /* newbie-regionen kriegen weniger ab */
|
|
||||||
|
|
||||||
if (!undead || r->age < 20) continue;
|
|
||||||
|
|
||||||
switch(rng_int()%3) {
|
|
||||||
case 0:
|
|
||||||
rc = new_race[RC_SKELETON]; break;
|
|
||||||
case 1:
|
|
||||||
rc = new_race[RC_ZOMBIE]; break;
|
|
||||||
default:
|
|
||||||
rc = new_race[RC_GHOUL]; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
u = createunit(r, monsters, undead, rc);
|
|
||||||
fset(u, UFL_ISNEW|UFL_MOVED);
|
|
||||||
if ((rc == new_race[RC_SKELETON] || rc == new_race[RC_ZOMBIE]) && rng_int()%10 < 4) {
|
|
||||||
equip_unit(u, get_equipment("rising_undead"));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i=0;i < MAXSKILLS;i++) {
|
|
||||||
if (rc->bonus[i] >= 1) {
|
|
||||||
set_level(u, (skill_t)i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
u->hp = unit_max_hp(u) * u->number;
|
|
||||||
|
|
||||||
deathcounts(r, -undead);
|
|
||||||
name_unit(u);
|
|
||||||
|
|
||||||
if (verbosity>=2) {
|
|
||||||
log_printf("%d %s in %s.\n", u->number,
|
|
||||||
LOC(default_locale, rc_name(u->race, u->number!=1)), regionname(r, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
message * msg = msg_message("undeadrise", "region", r);
|
|
||||||
add_message(&r->msgs, msg);
|
|
||||||
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)) continue;
|
|
||||||
fset(u->faction, FFL_SELECT);
|
|
||||||
add_message(&u->faction->msgs, msg);
|
|
||||||
}
|
|
||||||
msg_release(msg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int i = deathcount(r);
|
|
||||||
if (i) {
|
|
||||||
/* Gräber verwittern, 3% der Untoten finden die ewige Ruhe */
|
|
||||||
deathcounts(r, (int)(-i*0.03));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,16 +25,8 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DRAGON_RANGE 20 /* Max. Distanz zum nächsten Drachenziel */
|
void monster_kills_peasants(struct unit * u);
|
||||||
|
boolean monster_is_waiting(const struct unit * u);
|
||||||
void age_illusion(struct unit *u);
|
|
||||||
|
|
||||||
void monsters_kill_peasants(struct unit * u);
|
|
||||||
void plan_monsters(void);
|
|
||||||
struct unit *random_unit(const struct region * r);
|
|
||||||
|
|
||||||
extern void spawn_undead(void);
|
|
||||||
extern void spawn_dragons(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,6 +425,37 @@ chaosterrain(void)
|
||||||
return types[rng_int() % numtypes];
|
return types[rng_int() % numtypes];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unit *
|
||||||
|
random_unit(const region * r)
|
||||||
|
{
|
||||||
|
int c = 0;
|
||||||
|
int n;
|
||||||
|
unit *u;
|
||||||
|
|
||||||
|
for (u = r->units; u; u = u->next) {
|
||||||
|
if (u->race != new_race[RC_SPELL]) {
|
||||||
|
c += u->number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
n = rng_int() % c;
|
||||||
|
c = 0;
|
||||||
|
u = r->units;
|
||||||
|
|
||||||
|
while (u && c < n) {
|
||||||
|
if (u->race != new_race[RC_SPELL]) {
|
||||||
|
c += u->number;
|
||||||
|
}
|
||||||
|
u = u->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
chaos(region * r)
|
chaos(region * r)
|
||||||
{
|
{
|
||||||
|
@ -978,38 +1009,6 @@ godcurse(void)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unit *
|
|
||||||
split_unit(region * r, unit *u)
|
|
||||||
{
|
|
||||||
unit *u2 = create_unit(r, u->faction, 0, u->race, 0, u->name, u);
|
|
||||||
int newsize = u->number/2;
|
|
||||||
|
|
||||||
if (u->display) {
|
|
||||||
free(u2->display);
|
|
||||||
u2->display = strdup(u->display);
|
|
||||||
}
|
|
||||||
transfermen(u, u2, newsize);
|
|
||||||
return u2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
check_split(void)
|
|
||||||
{
|
|
||||||
region *r;
|
|
||||||
unit *u;
|
|
||||||
|
|
||||||
for(r=regions;r;r=r->next) {
|
|
||||||
for(u=r->units;u;u=u->next) {
|
|
||||||
if(is_monsters(u->faction)) {
|
|
||||||
if(u->number > u->race->splitsize) {
|
|
||||||
unit * u2 = split_unit(r, u);
|
|
||||||
fset(u2, UFL_ISNEW|UFL_MOVED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** handles the "orcish" curse that makes units grow like old orks
|
/** handles the "orcish" curse that makes units grow like old orks
|
||||||
* This would probably be better handled in an age-function for the curse,
|
* This would probably be better handled in an age-function for the curse,
|
||||||
* but it's now being called by randomevents()
|
* but it's now being called by randomevents()
|
||||||
|
@ -1273,5 +1272,4 @@ randomevents(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dissolve_units();
|
dissolve_units();
|
||||||
check_split();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,9 +92,6 @@
|
||||||
#include <util/patricia.h>
|
#include <util/patricia.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* exported variables */
|
|
||||||
region *regions;
|
|
||||||
faction *factions;
|
|
||||||
struct settings global = {
|
struct settings global = {
|
||||||
"Eressea", /* gamename */
|
"Eressea", /* gamename */
|
||||||
};
|
};
|
||||||
|
|
|
@ -166,9 +166,6 @@ extern int findoption(const char *s, const struct locale * lang);
|
||||||
/* special units */
|
/* special units */
|
||||||
void make_undead_unit(struct unit *);
|
void make_undead_unit(struct unit *);
|
||||||
|
|
||||||
extern struct region *regions;
|
|
||||||
extern struct faction *factions;
|
|
||||||
|
|
||||||
void addstrlist(strlist ** SP, const char *s);
|
void addstrlist(strlist ** SP, const char *s);
|
||||||
|
|
||||||
int armedmen(const struct unit * u, boolean siege_weapons);
|
int armedmen(const struct unit * u, boolean siege_weapons);
|
||||||
|
|
|
@ -49,6 +49,8 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
faction *factions;
|
||||||
|
|
||||||
/** remove the faction from memory.
|
/** remove the faction from memory.
|
||||||
* this frees all memory that's only accessible through the faction,
|
* this frees all memory that's only accessible through the faction,
|
||||||
* but you should still call funhash and remove the faction from the
|
* but you should still call funhash and remove the faction from the
|
||||||
|
|
|
@ -103,6 +103,8 @@ typedef struct faction {
|
||||||
struct seen_region ** seen;
|
struct seen_region ** seen;
|
||||||
} faction;
|
} faction;
|
||||||
|
|
||||||
|
extern struct faction *factions;
|
||||||
|
|
||||||
typedef struct faction_list {
|
typedef struct faction_list {
|
||||||
struct faction_list * next;
|
struct faction_list * next;
|
||||||
struct faction * data;
|
struct faction * data;
|
||||||
|
|
|
@ -64,6 +64,8 @@
|
||||||
|
|
||||||
extern int dice_rand(const char *s);
|
extern int dice_rand(const char *s);
|
||||||
|
|
||||||
|
region *regions;
|
||||||
|
|
||||||
int
|
int
|
||||||
get_maxluxuries()
|
get_maxluxuries()
|
||||||
{
|
{
|
||||||
|
|
|
@ -137,6 +137,8 @@ typedef struct region {
|
||||||
#endif
|
#endif
|
||||||
} region;
|
} region;
|
||||||
|
|
||||||
|
extern struct region *regions;
|
||||||
|
|
||||||
typedef struct region_list {
|
typedef struct region_list {
|
||||||
struct region_list * next;
|
struct region_list * next;
|
||||||
struct region * data;
|
struct region * data;
|
||||||
|
|
Loading…
Reference in a new issue