2015-10-11 21:19:38 +02:00
|
|
|
|
#include <platform.h>
|
|
|
|
|
#include <kernel/config.h>
|
|
|
|
|
#include "piracy.h"
|
|
|
|
|
|
|
|
|
|
#include "direction.h"
|
|
|
|
|
#include "keyword.h"
|
|
|
|
|
#include "move.h"
|
|
|
|
|
|
2015-11-24 18:52:09 +01:00
|
|
|
|
#include <kernel/ally.h>
|
2015-10-11 21:19:38 +02:00
|
|
|
|
#include <kernel/faction.h>
|
|
|
|
|
#include <kernel/messages.h>
|
|
|
|
|
#include <kernel/order.h>
|
2015-11-17 11:25:58 +01:00
|
|
|
|
#include <kernel/race.h>
|
2015-10-11 21:19:38 +02:00
|
|
|
|
#include <kernel/region.h>
|
|
|
|
|
#include <kernel/ship.h>
|
|
|
|
|
#include <kernel/terrain.h>
|
|
|
|
|
#include <kernel/unit.h>
|
|
|
|
|
|
|
|
|
|
#include <util/attrib.h>
|
|
|
|
|
#include <util/base36.h>
|
|
|
|
|
#include <util/goodies.h>
|
|
|
|
|
#include <util/language.h>
|
|
|
|
|
#include <util/parser.h>
|
|
|
|
|
#include <util/rng.h>
|
|
|
|
|
#include <util/message.h>
|
|
|
|
|
|
|
|
|
|
#include <attributes/otherfaction.h>
|
|
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
typedef struct piracy_data {
|
|
|
|
|
const struct faction *pirate;
|
|
|
|
|
const struct faction *target;
|
|
|
|
|
direction_t dir;
|
|
|
|
|
} piracy_data;
|
|
|
|
|
|
|
|
|
|
static void piracy_init(struct attrib *a)
|
|
|
|
|
{
|
|
|
|
|
a->data.v = calloc(1, sizeof(piracy_data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void piracy_done(struct attrib *a)
|
|
|
|
|
{
|
|
|
|
|
free(a->data.v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static attrib_type at_piracy_direction = {
|
|
|
|
|
"piracy_direction",
|
|
|
|
|
piracy_init,
|
|
|
|
|
piracy_done,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static attrib *mk_piracy(const faction * pirate, const faction * target,
|
|
|
|
|
direction_t target_dir)
|
|
|
|
|
{
|
|
|
|
|
attrib *a = a_new(&at_piracy_direction);
|
|
|
|
|
piracy_data *data = a->data.v;
|
|
|
|
|
data->pirate = pirate;
|
|
|
|
|
data->target = target;
|
|
|
|
|
data->dir = target_dir;
|
|
|
|
|
return a;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-12 16:30:56 +02:00
|
|
|
|
static bool validate_pirate(unit *u, order *ord) {
|
2015-11-17 11:25:58 +01:00
|
|
|
|
if (fval(u_race(u), RCF_SWIM | RCF_FLY))
|
|
|
|
|
return true;
|
2015-10-12 16:30:56 +02:00
|
|
|
|
if (!u->ship) {
|
|
|
|
|
cmistake(u, ord, 144, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!u->ship || u != ship_owner(u->ship)) {
|
|
|
|
|
cmistake(u, ord, 146, MSG_MOVE);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-12 18:54:47 +02:00
|
|
|
|
int *parse_ids(const order *ord) {
|
2015-10-11 21:19:38 +02:00
|
|
|
|
const char *s;
|
2015-10-12 18:54:47 +02:00
|
|
|
|
int *il = NULL;
|
2015-10-11 21:19:38 +02:00
|
|
|
|
|
|
|
|
|
init_order(ord);
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
if (s != NULL && *s) {
|
|
|
|
|
il = intlist_init();
|
|
|
|
|
while (s && *s) {
|
|
|
|
|
il = intlist_add(il, atoi36(s));
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-12 18:54:47 +02:00
|
|
|
|
return il;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
direction_t find_piracy_target(unit *u, int *il) {
|
|
|
|
|
attrib *a;
|
|
|
|
|
region *r = u->region;
|
2015-10-11 21:19:38 +02:00
|
|
|
|
|
|
|
|
|
for (a = a_find(r->attribs, &at_piracy_direction);
|
|
|
|
|
a && a->type == &at_piracy_direction; a = a->next) {
|
|
|
|
|
piracy_data *data = a->data.v;
|
|
|
|
|
const faction *p = data->pirate;
|
|
|
|
|
const faction *t = data->target;
|
|
|
|
|
|
|
|
|
|
if (alliedunit(u, p, HELP_FIGHT)) {
|
|
|
|
|
if (il == 0 || (t && intlist_find(il, t->no))) {
|
2015-10-12 18:54:47 +02:00
|
|
|
|
return data->dir;
|
2015-10-11 21:19:38 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-12 18:54:47 +02:00
|
|
|
|
return NODIRECTION;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-01 21:40:07 +02:00
|
|
|
|
void piracy_cmd(unit * u)
|
2015-10-12 18:54:47 +02:00
|
|
|
|
{
|
2016-09-01 21:40:07 +02:00
|
|
|
|
order *ord;
|
2015-10-12 18:54:47 +02:00
|
|
|
|
region *r = u->region;
|
|
|
|
|
ship *sh = u->ship, *sh2;
|
2015-10-12 19:40:20 +02:00
|
|
|
|
direction_t target_dir;
|
2015-10-12 18:54:47 +02:00
|
|
|
|
struct {
|
|
|
|
|
const faction *target;
|
|
|
|
|
int value;
|
|
|
|
|
} aff[MAXDIRECTIONS];
|
|
|
|
|
int saff = 0;
|
|
|
|
|
int *il;
|
|
|
|
|
|
2016-09-01 21:40:07 +02:00
|
|
|
|
if (!validate_pirate(u, u->thisorder)) {
|
2015-10-12 18:54:47 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-01 21:40:07 +02:00
|
|
|
|
il = parse_ids(u->thisorder);
|
2015-10-12 18:54:47 +02:00
|
|
|
|
/* Feststellen, ob schon ein anderer alliierter Pirat ein
|
|
|
|
|
* Ziel gefunden hat. */
|
|
|
|
|
|
|
|
|
|
target_dir = find_piracy_target(u, il);
|
2015-10-11 21:19:38 +02:00
|
|
|
|
|
|
|
|
|
/* Wenn nicht, sehen wir, ob wir ein Ziel finden. */
|
|
|
|
|
|
|
|
|
|
if (target_dir == NODIRECTION) {
|
2015-10-12 19:40:20 +02:00
|
|
|
|
direction_t dir;
|
2015-10-11 21:19:38 +02:00
|
|
|
|
/* Einheit ist also Kapit<69>n. Jetzt gucken, in wievielen
|
|
|
|
|
* Nachbarregionen potentielle Opfer sind. */
|
|
|
|
|
|
|
|
|
|
for (dir = 0; dir < MAXDIRECTIONS; dir++) {
|
|
|
|
|
region *rc = rconnect(r, dir);
|
|
|
|
|
aff[dir].value = 0;
|
|
|
|
|
aff[dir].target = 0;
|
2015-12-01 21:54:00 +01:00
|
|
|
|
// TODO this could still result in an illegal movement order (through a wall or whatever)
|
|
|
|
|
// which will be prevented by move_cmd below
|
|
|
|
|
if (rc &&
|
2016-06-10 20:55:27 +02:00
|
|
|
|
((sh && !fval(rc->terrain, FORBIDDEN_REGION) && can_takeoff(sh, r, rc))
|
2015-12-01 21:54:00 +01:00
|
|
|
|
|| (canswim(u) && fval(rc->terrain, SWIM_INTO) && fval(rc->terrain, SEA_REGION)))) {
|
2015-10-11 21:19:38 +02:00
|
|
|
|
|
|
|
|
|
for (sh2 = rc->ships; sh2; sh2 = sh2->next) {
|
|
|
|
|
unit *cap = ship_owner(sh2);
|
|
|
|
|
if (cap) {
|
|
|
|
|
faction *f = visible_faction(cap->faction, cap);
|
|
|
|
|
if (alliedunit(u, f, HELP_FIGHT))
|
|
|
|
|
continue;
|
2015-10-12 18:54:47 +02:00
|
|
|
|
if (!il || intlist_find(il, cap->faction->no)) { // TODO: shouldn't this be f->no?
|
2015-10-11 21:19:38 +02:00
|
|
|
|
++aff[dir].value;
|
|
|
|
|
if (rng_int() % aff[dir].value == 0) {
|
|
|
|
|
aff[dir].target = f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Und aufaddieren. */
|
|
|
|
|
saff += aff[dir].value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (saff != 0) {
|
|
|
|
|
saff = rng_int() % saff;
|
|
|
|
|
for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
|
2015-10-30 15:17:39 +01:00
|
|
|
|
if (saff < aff[dir].value) {
|
|
|
|
|
target_dir = dir;
|
|
|
|
|
a_add(&r->attribs, mk_piracy(u->faction, aff[dir].target, target_dir));
|
2015-10-11 21:19:38 +02:00
|
|
|
|
break;
|
2015-10-30 15:17:39 +01:00
|
|
|
|
}
|
2015-10-11 21:19:38 +02:00
|
|
|
|
saff -= aff[dir].value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(il);
|
|
|
|
|
|
|
|
|
|
/* Wenn kein Ziel gefunden, entsprechende Meldung generieren */
|
|
|
|
|
if (target_dir == NODIRECTION) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("piratenovictim",
|
2015-12-01 21:54:00 +01:00
|
|
|
|
"ship unit region", sh, u, r));
|
2015-10-11 21:19:38 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Meldung generieren */
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("piratesawvictim",
|
2015-12-01 21:54:00 +01:00
|
|
|
|
"ship unit region dir", sh, u, r, target_dir));
|
2015-10-11 21:19:38 +02:00
|
|
|
|
|
|
|
|
|
/* Befehl konstruieren */
|
2016-09-01 21:40:07 +02:00
|
|
|
|
// TODO: why change u->thisorder?
|
|
|
|
|
// FIXME: when u->thisorder == ord, set_order calls free, destroys both.
|
|
|
|
|
ord = create_order(K_MOVE, u->faction->locale, "%s", LOC(u->faction->locale, directions[target_dir]));
|
2015-10-11 21:19:38 +02:00
|
|
|
|
|
|
|
|
|
/* Bewegung ausf<73>hren */
|
2016-09-01 21:40:07 +02:00
|
|
|
|
init_order(ord);
|
2016-08-20 19:25:44 +02:00
|
|
|
|
move_cmd(u, ord);
|
2015-10-11 21:19:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void age_piracy(region *r) {
|
|
|
|
|
a_removeall(&r->attribs, &at_piracy_direction);
|
|
|
|
|
}
|