forked from github/server
127 lines
3.3 KiB
C
127 lines
3.3 KiB
C
#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>
|
|
#include <util/log.h>
|
|
#include <kernel/attrib.h>
|
|
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
|
|
attrib_type at_lighthouse = {
|
|
"lighthouse"
|
|
/* Rest ist NULL; temporaeres, nicht alterndes Attribut */
|
|
};
|
|
|
|
bool is_lighthouse(const building_type *btype)
|
|
{
|
|
return is_building_type(btype, "lighthouse");
|
|
}
|
|
|
|
/* 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, since this may change more frequently.
|
|
*/
|
|
void update_lighthouse(building * lh)
|
|
{
|
|
region *r = lh->region;
|
|
assert(is_lighthouse(lh->type));
|
|
|
|
r->flags |= RF_LIGHTHOUSE;
|
|
if (lh->size >= 10) {
|
|
int d = lighthouse_range(lh);
|
|
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;
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void remove_lighthouse(const building *lh) {
|
|
building *b;
|
|
region * r = lh->region;
|
|
|
|
r->flags &= ~RF_LIGHTHOUSE;
|
|
for (b = r->buildings; b; b = b->next) {
|
|
if (b != lh && is_lighthouse(b->type)) {
|
|
update_lighthouse(b);
|
|
}
|
|
}
|
|
}
|
|
|
|
int lighthouse_range(const building * b)
|
|
{
|
|
if (b->size >= 10 && (b->flags & BLD_MAINTAINED)) {
|
|
return (int)log10(b->size) + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int lighthouse_view_distance(const building * b, const unit *u)
|
|
{
|
|
if (b->size >= 10 && (b->flags & BLD_MAINTAINED)) {
|
|
int maxd = lighthouse_range(b);
|
|
|
|
if (maxd > 0 && u && skill_enabled(SK_PERCEPTION)) {
|
|
int sk = effskill(u, SK_PERCEPTION, NULL) / 3;
|
|
assert(u->building == b);
|
|
if (maxd > sk) maxd = sk;
|
|
}
|
|
return maxd;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool lighthouse_guarded(const region * r)
|
|
{
|
|
attrib *a;
|
|
|
|
if (!r->attribs || !(r->terrain->flags & SEA_REGION)) {
|
|
return false;
|
|
}
|
|
for (a = a_find(r->attribs, &at_lighthouse); a && a->type == &at_lighthouse;
|
|
a = a->next) {
|
|
building *b = (building *)a->data.v;
|
|
|
|
assert(is_building_type(b->type, "lighthouse"));
|
|
if ((b->flags & BLD_MAINTAINED) && b->size >= 10) {
|
|
int maxd = (int)log10(b->size) + 1;
|
|
int d = distance(r, b->region);
|
|
assert(maxd >= d);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|