2014-12-17 17:22:26 +01:00
|
|
|
|
#include <platform.h>
|
|
|
|
|
#include "lighthouse.h"
|
|
|
|
|
|
|
|
|
|
#include <kernel/config.h>
|
|
|
|
|
#include <kernel/building.h>
|
|
|
|
|
#include <kernel/faction.h>
|
|
|
|
|
#include <kernel/plane.h>
|
|
|
|
|
#include <kernel/region.h>
|
|
|
|
|
#include <kernel/terrain.h>
|
|
|
|
|
#include <kernel/unit.h>
|
2016-09-11 11:02:04 +02:00
|
|
|
|
#include <util/log.h>
|
2014-12-17 17:22:26 +01:00
|
|
|
|
#include <util/attrib.h>
|
|
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
2016-12-16 17:16:10 +01:00
|
|
|
|
attrib_type at_lighthouse = {
|
2014-12-17 17:22:26 +01:00
|
|
|
|
"lighthouse"
|
2016-11-19 15:19:23 +01:00
|
|
|
|
/* Rest ist NULL; tempor<6F>res, nicht alterndes Attribut */
|
2014-12-17 17:22:26 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* update_lighthouse: call this function whenever the size of a lighthouse changes
|
|
|
|
|
* it adds temporary markers to the surrounding regions.
|
|
|
|
|
* The existence of markers says nothing about the quality of the observer in
|
|
|
|
|
* the lighthouse, for this may change more frequently.
|
|
|
|
|
*/
|
|
|
|
|
void update_lighthouse(building * lh)
|
|
|
|
|
{
|
2016-09-18 10:24:08 +02:00
|
|
|
|
if (is_building_type(lh->type, "lighthouse")) {
|
2014-12-17 17:22:26 +01:00
|
|
|
|
region *r = lh->region;
|
|
|
|
|
|
2016-09-11 11:02:04 +02:00
|
|
|
|
r->flags |= RF_LIGHTHOUSE;
|
2016-09-18 10:24:08 +02:00
|
|
|
|
if (lh->size > 0) {
|
|
|
|
|
int d = (int)log10(lh->size) + 1;
|
|
|
|
|
int x;
|
|
|
|
|
for (x = -d; x <= d; ++x) {
|
|
|
|
|
int y;
|
|
|
|
|
for (y = -d; y <= d; ++y) {
|
|
|
|
|
attrib *a;
|
|
|
|
|
region *r2;
|
|
|
|
|
int px = r->x + x, py = r->y + y;
|
2014-12-17 17:22:26 +01:00
|
|
|
|
|
2016-09-18 10:24:08 +02:00
|
|
|
|
pnormalize(&px, &py, rplane(r));
|
|
|
|
|
r2 = findregion(px, py);
|
|
|
|
|
if (!r2 || !fval(r2->terrain, SEA_REGION))
|
|
|
|
|
continue;
|
|
|
|
|
if (distance(r, r2) > d)
|
|
|
|
|
continue;
|
|
|
|
|
a = a_find(r2->attribs, &at_lighthouse);
|
|
|
|
|
while (a && a->type == &at_lighthouse) {
|
|
|
|
|
building *b = (building *)a->data.v;
|
|
|
|
|
if (b == lh)
|
|
|
|
|
break;
|
|
|
|
|
a = a->next;
|
|
|
|
|
}
|
|
|
|
|
if (!a) {
|
|
|
|
|
a = a_add(&r2->attribs, a_new(&at_lighthouse));
|
|
|
|
|
a->data.v = (void *)lh;
|
|
|
|
|
}
|
2014-12-17 17:22:26 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int lighthouse_range(const building * b, const faction * f)
|
|
|
|
|
{
|
|
|
|
|
int d = 0;
|
2016-08-21 20:12:28 +02:00
|
|
|
|
if (fval(b, BLD_MAINTAINED) && b->size >= 10) {
|
2014-12-17 17:22:26 +01:00
|
|
|
|
int maxd = (int)log10(b->size) + 1;
|
|
|
|
|
|
|
|
|
|
if (skill_enabled(SK_PERCEPTION)) {
|
|
|
|
|
region *r = b->region;
|
|
|
|
|
int c = 0;
|
2016-09-17 13:20:02 +02:00
|
|
|
|
int cap = buildingcapacity(b);
|
2016-10-05 20:36:01 +02:00
|
|
|
|
unit *u, *uown = building_owner(b);
|
2016-09-17 13:20:02 +02:00
|
|
|
|
|
2014-12-17 17:22:26 +01:00
|
|
|
|
for (u = r->units; u; u = u->next) {
|
2016-10-05 20:36:01 +02:00
|
|
|
|
if (u->building == b || u == uown) {
|
|
|
|
|
c += u->number;
|
2016-09-17 13:20:02 +02:00
|
|
|
|
if (c > cap) {
|
2014-12-17 17:22:26 +01:00
|
|
|
|
break;
|
2016-09-17 13:20:02 +02:00
|
|
|
|
}
|
|
|
|
|
else if (f == NULL || u->faction == f) {
|
2015-08-27 16:16:55 +02:00
|
|
|
|
int sk = effskill(u, SK_PERCEPTION, 0) / 3;
|
2017-01-10 16:31:05 +01:00
|
|
|
|
d = MAX(d, sk);
|
|
|
|
|
d = MIN(maxd, d);
|
2014-12-17 17:22:26 +01:00
|
|
|
|
if (d == maxd)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (c)
|
|
|
|
|
break; /* first unit that's no longer in the house ends the search */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* E3A rule: no perception req'd */
|
|
|
|
|
return maxd;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool check_leuchtturm(region * r, faction * f)
|
|
|
|
|
{
|
|
|
|
|
attrib *a;
|
|
|
|
|
|
2015-01-08 20:55:29 +01:00
|
|
|
|
if (!fval(r->terrain, SEA_REGION)) {
|
2014-12-17 17:22:26 +01:00
|
|
|
|
return false;
|
2015-01-08 20:55:29 +01:00
|
|
|
|
}
|
2014-12-17 17:22:26 +01:00
|
|
|
|
for (a = a_find(r->attribs, &at_lighthouse); a && a->type == &at_lighthouse;
|
|
|
|
|
a = a->next) {
|
|
|
|
|
building *b = (building *)a->data.v;
|
|
|
|
|
|
2016-08-30 10:19:19 +02:00
|
|
|
|
assert(is_building_type(b->type, "lighthouse"));
|
2016-08-21 20:12:28 +02:00
|
|
|
|
if (fval(b, BLD_MAINTAINED) && b->size >= 10) {
|
2014-12-17 17:22:26 +01:00
|
|
|
|
int maxd = (int)log10(b->size) + 1;
|
|
|
|
|
|
|
|
|
|
if (skill_enabled(SK_PERCEPTION) && f) {
|
|
|
|
|
region *r2 = b->region;
|
|
|
|
|
unit *u;
|
|
|
|
|
int c = 0;
|
|
|
|
|
int d = 0;
|
|
|
|
|
|
|
|
|
|
for (u = r2->units; u; u = u->next) {
|
|
|
|
|
if (u->building == b) {
|
|
|
|
|
c += u->number;
|
|
|
|
|
if (c > buildingcapacity(b))
|
|
|
|
|
break;
|
2016-11-19 15:19:23 +01:00
|
|
|
|
if (u->faction == f) {
|
2014-12-17 17:22:26 +01:00
|
|
|
|
if (!d)
|
|
|
|
|
d = distance(r, r2);
|
|
|
|
|
if (maxd < d)
|
|
|
|
|
break;
|
2015-08-27 16:16:55 +02:00
|
|
|
|
if (effskill(u, SK_PERCEPTION, 0) >= d * 3)
|
2014-12-17 17:22:26 +01:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (c)
|
|
|
|
|
break; /* first unit that's no longer in the house ends the search */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* E3A rule: no perception req'd */
|
2015-01-08 20:55:29 +01:00
|
|
|
|
return true;
|
2014-12-17 17:22:26 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|