2010-08-08 10:06:34 +02:00
|
|
|
|
/*
|
|
|
|
|
Copyright (c) 1998-2010, Enno Rehling <enno@eressea.de>
|
|
|
|
|
Katja Zedel <katze@felidae.kn-bremen.de
|
|
|
|
|
Christian Schlittchen <corwin@amber.kn-bremen.de>
|
|
|
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
|
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
#include <platform.h>
|
|
|
|
|
#include <kernel/config.h>
|
|
|
|
|
#include "spy.h"
|
|
|
|
|
|
|
|
|
|
/* kernel includes */
|
|
|
|
|
#include <kernel/build.h>
|
|
|
|
|
#include <kernel/reports.h>
|
|
|
|
|
#include <kernel/item.h>
|
|
|
|
|
#include <kernel/faction.h>
|
|
|
|
|
#include <kernel/magic.h>
|
|
|
|
|
#include <kernel/message.h>
|
|
|
|
|
#include <kernel/move.h>
|
|
|
|
|
#include <kernel/race.h>
|
|
|
|
|
#include <kernel/region.h>
|
|
|
|
|
#include <kernel/ship.h>
|
|
|
|
|
#include <kernel/skill.h>
|
|
|
|
|
#include <kernel/terrain.h>
|
|
|
|
|
#include <kernel/unit.h>
|
|
|
|
|
|
|
|
|
|
/* attributes includes */
|
|
|
|
|
#include <attributes/racename.h>
|
2010-09-03 08:29:33 +02:00
|
|
|
|
#include <attributes/otherfaction.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
/* util includes */
|
|
|
|
|
#include <util/attrib.h>
|
|
|
|
|
#include <util/base36.h>
|
|
|
|
|
#include <util/parser.h>
|
2011-02-25 16:27:44 +01:00
|
|
|
|
#include <util/quicklist.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include <util/rand.h>
|
|
|
|
|
#include <util/rng.h>
|
|
|
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
/* in spy steht der Unterschied zwischen Wahrnehmung des Opfers und
|
|
|
|
|
* Spionage des Spions */
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void spy_message(int spy, const unit * u, const unit * target)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const char *str = report_kampfstatus(target, u->faction->locale);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u,
|
|
|
|
|
target, str));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
if (spy > 20) {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
sc_mage *mage = get_mage(target);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* bei Magiern Zauberspr<70>che und Magiegebiet */
|
|
|
|
|
if (mage) {
|
2011-03-19 19:06:03 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type",
|
2011-03-07 08:02:35 +01:00
|
|
|
|
target, magic_school[mage->magietyp]));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (spy > 6) {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
faction *fv = visible_faction(u->faction, target);
|
|
|
|
|
if (fv && fv != target->faction) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* wahre Partei */
|
2011-03-07 08:02:35 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyreport_faction",
|
2011-04-30 06:50:12 +02:00
|
|
|
|
"target faction", target, target->faction));
|
2011-02-25 16:27:44 +01:00
|
|
|
|
ql_set_insert(&u->faction->seen_factions, target->faction);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (spy > 0) {
|
|
|
|
|
int first = 1;
|
|
|
|
|
int found = 0;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
skill *sv;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
char buf[4096];
|
|
|
|
|
|
|
|
|
|
buf[0] = 0;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
for (sv = target->skills; sv != target->skills + target->skill_size; ++sv) {
|
|
|
|
|
if (sv->level > 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
found++;
|
|
|
|
|
if (first == 1) {
|
|
|
|
|
first = 0;
|
|
|
|
|
} else {
|
|
|
|
|
strncat(buf, ", ", sizeof(buf));
|
|
|
|
|
}
|
2011-04-30 06:50:12 +02:00
|
|
|
|
strncat(buf, (const char *)skillname((skill_t)sv->id, u->faction->locale),
|
2011-03-07 08:02:35 +01:00
|
|
|
|
sizeof(buf));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
strncat(buf, " ", sizeof(buf));
|
2011-04-30 06:50:12 +02:00
|
|
|
|
strncat(buf, itoa10(eff_skill(target, (skill_t)sv->id, target->region)),
|
2011-03-07 08:02:35 +01:00
|
|
|
|
sizeof(buf));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (found) {
|
2011-03-19 19:06:03 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills",
|
2011-03-07 08:02:35 +01:00
|
|
|
|
target, buf));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target->items) {
|
2011-03-19 19:06:03 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items",
|
2011-03-07 08:02:35 +01:00
|
|
|
|
target, target->items));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
int spy_cmd(unit * u, struct order *ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
|
|
|
|
unit *target;
|
|
|
|
|
int spy, observe;
|
|
|
|
|
double spychance, observechance;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
region *r = u->region;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
target = getunit(r, u->faction);
|
|
|
|
|
|
|
|
|
|
if (!target) {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder,
|
|
|
|
|
"feedback_unit_not_found", ""));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!can_contact(r, u, target)) {
|
|
|
|
|
cmistake(u, u->thisorder, 24, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (eff_skill(u, SK_SPY, r) < 1) {
|
|
|
|
|
cmistake(u, u->thisorder, 39, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* Die Grundchance f<>r einen erfolgreichen Spionage-Versuch ist 10%.
|
2011-03-07 08:02:35 +01:00
|
|
|
|
* F<EFBFBD>r jeden Talentpunkt, den das Spionagetalent das Tarnungstalent
|
|
|
|
|
* des Opfers <EFBFBD>bersteigt, erh<EFBFBD>ht sich dieses um 5%*/
|
2010-08-08 10:06:34 +02:00
|
|
|
|
spy = eff_skill(u, SK_SPY, r) - eff_skill(target, SK_STEALTH, r);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
spychance = 0.1 + MAX(spy * 0.05, 0.0);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
if (chance(spychance)) {
|
|
|
|
|
produceexp(u, SK_SPY, u->number);
|
|
|
|
|
spy_message(spy, u, target);
|
|
|
|
|
} else {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyfail", "spy target", u, target));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* der Spion kann identifiziert werden, wenn das Opfer bessere
|
2011-03-07 08:02:35 +01:00
|
|
|
|
* Wahrnehmung als das Ziel Tarnung + Spionage/2 hat */
|
2010-08-08 10:06:34 +02:00
|
|
|
|
observe = eff_skill(target, SK_PERCEPTION, r)
|
2011-03-07 08:02:35 +01:00
|
|
|
|
- (effskill(u, SK_STEALTH) + eff_skill(u, SK_SPY, r) / 2);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
if (invisible(u, target) >= u->number) {
|
|
|
|
|
observe = MIN(observe, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Anschlie<69>end wird - unabh<62>ngig vom Erfolg - gew<65>rfelt, ob der
|
2011-03-07 08:02:35 +01:00
|
|
|
|
* Spionageversuch bemerkt wurde. Die Wahrscheinlich daf<EFBFBD>r ist (100 -
|
|
|
|
|
* SpionageSpion*5 + WahrnehmungOpfer*2)%. */
|
2010-08-08 10:06:34 +02:00
|
|
|
|
observechance = 1.0 - (eff_skill(u, SK_SPY, r) * 0.05)
|
|
|
|
|
+ (eff_skill(target, SK_PERCEPTION, r) * 0.02);
|
|
|
|
|
|
|
|
|
|
if (chance(observechance)) {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
ADDMSG(&target->faction->msgs, msg_message("spydetect",
|
|
|
|
|
"spy target", observe > 0 ? u : NULL, target));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void set_factionstealth(unit * u, faction * f)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
|
region *lastr = NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* for all units mu of our faction, check all the units in the region
|
2011-03-07 08:02:35 +01:00
|
|
|
|
* they are in, if their visible faction is f, it's ok. use lastr to
|
|
|
|
|
* avoid testing the same region twice in a row. */
|
|
|
|
|
unit *mu = u->faction->units;
|
|
|
|
|
while (mu != NULL) {
|
|
|
|
|
if (mu->number && mu->region != lastr) {
|
|
|
|
|
unit *ru = mu->region->units;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
lastr = mu->region;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
while (ru != NULL) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
if (ru->number) {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
faction *fv = visible_faction(f, ru);
|
|
|
|
|
if (fv == f) {
|
|
|
|
|
if (cansee(f, lastr, ru, 0))
|
|
|
|
|
break;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ru = ru->next;
|
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (ru != NULL)
|
|
|
|
|
break;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
mu = mu->nextF;
|
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (mu != NULL) {
|
|
|
|
|
attrib *a = a_find(u->attribs, &at_otherfaction);
|
|
|
|
|
if (!a)
|
|
|
|
|
a = a_add(&u->attribs, make_otherfaction(f));
|
|
|
|
|
else
|
|
|
|
|
a->data.v = f;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
int setstealth_cmd(unit * u, struct order *ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
|
|
|
|
const char *s;
|
2010-09-03 08:29:33 +02:00
|
|
|
|
int level, rule;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const race *trace;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
|
|
|
|
|
/* Tarne ohne Parameter: Setzt maximale Tarnung */
|
|
|
|
|
|
|
|
|
|
if (s == NULL || *s == 0) {
|
|
|
|
|
u_seteffstealth(u, -1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trace = findrace(s, u->faction->locale);
|
|
|
|
|
if (trace) {
|
|
|
|
|
/* D<>monen k<>nnen sich nur als andere Spielerrassen tarnen */
|
|
|
|
|
if (u->race == new_race[RC_DAEMON]) {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
race_t allowed[] = { RC_DWARF, RC_ELF, RC_ORC, RC_GOBLIN, RC_HUMAN,
|
2010-08-08 10:06:34 +02:00
|
|
|
|
RC_TROLL, RC_DAEMON, RC_INSECT, RC_HALFLING, RC_CAT, RC_AQUARIAN,
|
2011-03-07 08:02:35 +01:00
|
|
|
|
NORACE
|
|
|
|
|
};
|
2010-08-08 10:06:34 +02:00
|
|
|
|
int i;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
for (i = 0; allowed[i] != NORACE; ++i)
|
|
|
|
|
if (new_race[allowed[i]] == trace)
|
|
|
|
|
break;
|
|
|
|
|
if (new_race[allowed[i]] == trace) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
u->irace = trace;
|
|
|
|
|
if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs))
|
|
|
|
|
set_racename(&u->attribs, NULL);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Singdrachen k<>nnen sich nur als Drachen tarnen */
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (u->race == new_race[RC_SONGDRAGON]
|
|
|
|
|
|| u->race == new_race[RC_BIRTHDAYDRAGON]) {
|
|
|
|
|
if (trace == new_race[RC_SONGDRAGON] || trace == new_race[RC_FIREDRAGON]
|
|
|
|
|
|| trace == new_race[RC_DRAGON] || trace == new_race[RC_WYRM]) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
u->irace = trace;
|
|
|
|
|
if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs))
|
|
|
|
|
set_racename(&u->attribs, NULL);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* D<>momen und Illusionsparteien k<>nnen sich als andere race tarnen */
|
|
|
|
|
if (u->race->flags & RCF_SHAPESHIFT) {
|
|
|
|
|
if (playerrace(trace)) {
|
|
|
|
|
u->irace = trace;
|
|
|
|
|
if ((u->race->flags & RCF_SHAPESHIFTANY) && get_racename(u->attribs))
|
|
|
|
|
set_racename(&u->attribs, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
switch (findparam(s, u->faction->locale)) {
|
|
|
|
|
case P_FACTION:
|
|
|
|
|
/* TARNE PARTEI [NICHT|NUMMER abcd] */
|
|
|
|
|
rule = rule_stealth_faction();
|
2012-03-05 04:21:00 +01:00
|
|
|
|
if (!rule) {
|
|
|
|
|
/* TARNE PARTEI is disabled */
|
2011-03-07 08:02:35 +01:00
|
|
|
|
break;
|
2012-03-05 04:21:00 +01:00
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
s = getstrtoken();
|
2012-03-05 04:21:00 +01:00
|
|
|
|
if (rule&1) {
|
|
|
|
|
if (!s || *s == 0) {
|
|
|
|
|
fset(u, UFL_ANON_FACTION);
|
|
|
|
|
break;
|
|
|
|
|
} else if (findparam(s, u->faction->locale) == P_NOT) {
|
|
|
|
|
freset(u, UFL_ANON_FACTION);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (rule&2) {
|
|
|
|
|
if (findkeyword(s, u->faction->locale) == K_NUMBER) {
|
|
|
|
|
const char *s2 = (const char *)getstrtoken();
|
|
|
|
|
int nr = -1;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2012-03-05 04:21:00 +01:00
|
|
|
|
if (s2) {
|
|
|
|
|
nr = atoi36(s2);
|
|
|
|
|
}
|
|
|
|
|
if (!s2 || *s2 == 0 || nr == u->faction->no) {
|
|
|
|
|
a_removeall(&u->attribs, &at_otherfaction);
|
|
|
|
|
break;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
} else {
|
2012-03-05 04:21:00 +01:00
|
|
|
|
struct faction *f = findfaction(nr);
|
|
|
|
|
if (f == NULL) {
|
|
|
|
|
cmistake(u, ord, 66, MSG_EVENT);
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
set_factionstealth(u, f);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-05 04:21:00 +01:00
|
|
|
|
cmistake(u, ord, 289, MSG_EVENT);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
break;
|
|
|
|
|
case P_ANY:
|
|
|
|
|
case P_NOT:
|
|
|
|
|
/* TARNE ALLES (was nicht so alles geht?) */
|
|
|
|
|
u_seteffstealth(u, -1);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (isdigit(s[0])) {
|
|
|
|
|
/* Tarnungslevel setzen */
|
|
|
|
|
level = atoi((const char *)s);
|
|
|
|
|
if (level > effskill(u, SK_STEALTH)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth",
|
|
|
|
|
""));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
u_seteffstealth(u, level);
|
|
|
|
|
} else if (u->race->flags & RCF_SHAPESHIFTANY) {
|
|
|
|
|
set_racename(&u->attribs, s);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static int crew_skill(region * r, faction * f, ship * sh, skill_t sk)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
|
|
|
|
int value = 0;
|
|
|
|
|
unit *u;
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
for (u = r->units; u; u = u->next) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
if (u->ship == sh && u->faction == f) {
|
|
|
|
|
int s = eff_skill(u, sk, r);
|
|
|
|
|
value = MAX(s, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static int try_destruction(unit * u, unit * u2, const ship * sh, int skilldiff)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
|
|
|
|
const char *destruction_success_msg = "destroy_ship_0";
|
|
|
|
|
const char *destruction_failed_msg = "destroy_ship_1";
|
|
|
|
|
const char *destruction_detected_msg = "destroy_ship_2";
|
|
|
|
|
const char *detect_failure_msg = "destroy_ship_3";
|
|
|
|
|
const char *object_destroyed_msg = "destroy_ship_4";
|
|
|
|
|
|
|
|
|
|
if (skilldiff == 0) {
|
|
|
|
|
/* tell the unit that the attempt failed: */
|
2011-03-07 08:02:35 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message(destruction_failed_msg, "ship unit",
|
|
|
|
|
sh, u));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* tell the enemy about the attempt: */
|
|
|
|
|
if (u2) {
|
|
|
|
|
ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh));
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (skilldiff < 0) {
|
|
|
|
|
/* tell the unit that the attempt was detected: */
|
2011-03-07 08:02:35 +01:00
|
|
|
|
ADDMSG(&u2->faction->msgs, msg_message(destruction_detected_msg,
|
|
|
|
|
"ship unit", sh, u));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* tell the enemy whodunit: */
|
|
|
|
|
if (u2) {
|
|
|
|
|
ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh));
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
/* tell the unit that the attempt succeeded */
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message(destruction_success_msg, "ship unit",
|
|
|
|
|
sh, u));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
if (u2) {
|
|
|
|
|
ADDMSG(&u2->faction->msgs, msg_message(object_destroyed_msg, "ship", sh));
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
return 1; /* success */
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void sink_ship(region * r, ship * sh, const char *name, unit * saboteur)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
|
|
|
|
unit **ui, *u;
|
|
|
|
|
region *safety = r;
|
|
|
|
|
int i;
|
|
|
|
|
direction_t d;
|
|
|
|
|
double probability = 0.0;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
message *sink_msg = NULL;
|
|
|
|
|
faction *f;
|
|
|
|
|
|
|
|
|
|
for (f = NULL, u = r->units; u; u = u->next) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* slight optimization to avoid dereferencing u->faction each time */
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (f != u->faction) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
f = u->faction;
|
|
|
|
|
freset(f, FFL_SELECT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* figure out what a unit's chances of survival are: */
|
|
|
|
|
if (!fval(r->terrain, SEA_REGION)) {
|
|
|
|
|
probability = CANAL_SWIMMER_CHANCE;
|
|
|
|
|
} else {
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
region *rn = rconnect(r, d);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
if (!fval(rn->terrain, SEA_REGION) && !move_blocked(NULL, r, rn)) {
|
|
|
|
|
safety = rn;
|
|
|
|
|
probability = OCEAN_SWIMMER_CHANCE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (ui = &r->units; *ui; ui = &(*ui)->next) {
|
|
|
|
|
unit *u = *ui;
|
|
|
|
|
|
|
|
|
|
/* inform this faction about the sinking ship: */
|
|
|
|
|
if (!fval(u->faction, FFL_SELECT)) {
|
|
|
|
|
fset(u->faction, FFL_SELECT);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (sink_msg == NULL) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
sink_msg = msg_message("sink_msg", "ship region", sh, r);
|
|
|
|
|
}
|
|
|
|
|
add_message(&f->msgs, sink_msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (u->ship == sh) {
|
|
|
|
|
int dead = 0;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
message *msg;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
/* if this fails, I misunderstood something: */
|
|
|
|
|
for (i = 0; i != u->number; ++i)
|
|
|
|
|
if (chance(probability))
|
|
|
|
|
++dead;
|
|
|
|
|
|
|
|
|
|
if (dead != u->number) {
|
|
|
|
|
/* she will live. but her items get stripped */
|
|
|
|
|
if (dead > 0) {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
msg =
|
|
|
|
|
msg_message("sink_lost_msg", "dead region unit", dead, safety, u);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
} else {
|
|
|
|
|
msg = msg_message("sink_saved_msg", "region unit", safety, u);
|
|
|
|
|
}
|
|
|
|
|
set_leftship(u, u->ship);
|
|
|
|
|
u->ship = 0;
|
|
|
|
|
if (r != safety) {
|
|
|
|
|
setguard(u, GUARD_NONE);
|
|
|
|
|
}
|
|
|
|
|
while (u->items) {
|
|
|
|
|
i_remove(&u->items, u->items);
|
|
|
|
|
}
|
|
|
|
|
move_unit(u, safety, NULL);
|
|
|
|
|
} else {
|
|
|
|
|
msg = msg_message("sink_lost_msg", "dead region unit", dead, NULL, u);
|
|
|
|
|
}
|
|
|
|
|
add_message(&u->faction->msgs, msg);
|
|
|
|
|
msg_release(msg);
|
|
|
|
|
if (dead == u->number) {
|
|
|
|
|
/* the poor creature, she dies */
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (remove_unit(ui, u) != 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
ui = &u->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (sink_msg)
|
|
|
|
|
msg_release(sink_msg);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* finally, get rid of the ship */
|
|
|
|
|
remove_ship(&sh->region->ships, sh);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
int sabotage_cmd(unit * u, struct order *ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
int i;
|
|
|
|
|
ship *sh;
|
|
|
|
|
unit *u2;
|
|
|
|
|
char buffer[DISPLAYSIZE];
|
2011-03-07 08:02:35 +01:00
|
|
|
|
region *r = u->region;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
int skdiff;
|
|
|
|
|
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
|
|
|
|
|
i = findparam(s, u->faction->locale);
|
|
|
|
|
|
|
|
|
|
switch (i) {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
case P_SHIP:
|
|
|
|
|
sh = u->ship;
|
|
|
|
|
if (!sh) {
|
|
|
|
|
cmistake(u, u->thisorder, 144, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
u2 = shipowner(sh);
|
|
|
|
|
skdiff =
|
|
|
|
|
eff_skill(u, SK_SPY, r) - crew_skill(r, u2->faction, sh, SK_PERCEPTION);
|
|
|
|
|
if (try_destruction(u, u2, sh, skdiff)) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
sink_ship(r, sh, buffer, u);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cmistake(u, u->thisorder, 9, MSG_EVENT);
|
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|