2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
2007-07-17 17:33:48 +02:00
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* Eressea PB(E)M host Copyright (C) 1998-2003
|
|
|
|
|
* Christian Schlittchen (corwin@amber.kn-bremen.de)
|
|
|
|
|
* Katja Zedel (katze@felidae.kn-bremen.de)
|
|
|
|
|
* Henning Peters (faroul@beyond.kn-bremen.de)
|
2007-09-02 20:11:17 +02:00
|
|
|
|
* Enno Rehling (enno@eressea.de)
|
2007-07-17 17:33:48 +02:00
|
|
|
|
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
|
|
|
|
*
|
|
|
|
|
* based on:
|
|
|
|
|
*
|
|
|
|
|
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
|
|
|
|
|
* Atlantis v1.7 Copyright 1996 by Alex Schr<EFBFBD>der
|
|
|
|
|
*
|
|
|
|
|
* This program may not be used, modified or distributed without
|
|
|
|
|
* prior permission by the authors of Eressea.
|
|
|
|
|
* This program may not be sold or used commercially without prior written
|
|
|
|
|
* permission from the authors.
|
|
|
|
|
*/
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "eressea.h"
|
|
|
|
|
#include "spy.h"
|
|
|
|
|
|
|
|
|
|
/* kernel includes */
|
2005-01-03 22:28:21 +01:00
|
|
|
|
#include <kernel/build.h>
|
|
|
|
|
#include <kernel/reports.h>
|
2005-10-25 14:38:01 +02:00
|
|
|
|
#include <kernel/item.h>
|
|
|
|
|
#include <kernel/karma.h>
|
|
|
|
|
#include <kernel/faction.h>
|
|
|
|
|
#include <kernel/magic.h>
|
|
|
|
|
#include <kernel/message.h>
|
2007-08-05 14:26:46 +02:00
|
|
|
|
#include <kernel/move.h>
|
2005-10-25 14:38:01 +02:00
|
|
|
|
#include <kernel/race.h>
|
|
|
|
|
#include <kernel/region.h>
|
|
|
|
|
#include <kernel/ship.h>
|
|
|
|
|
#include <kernel/skill.h>
|
|
|
|
|
#include <kernel/terrain.h>
|
|
|
|
|
#include <kernel/unit.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
/* attributes includes */
|
|
|
|
|
#include <attributes/racename.h>
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* util includes */
|
2007-06-20 02:34:02 +02:00
|
|
|
|
#include <util/attrib.h>
|
2007-08-08 09:43:24 +02:00
|
|
|
|
#include <util/base36.h>
|
2007-06-22 00:31:28 +02:00
|
|
|
|
#include <util/parser.h>
|
2004-02-09 23:20:40 +01:00
|
|
|
|
#include <util/rand.h>
|
2006-02-19 23:43:56 +01:00
|
|
|
|
#include <util/rng.h>
|
2007-06-20 02:34:02 +02:00
|
|
|
|
#include <util/vset.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <assert.h>
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
#include <ctype.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2001-04-14 14:11:45 +02:00
|
|
|
|
#include <attributes/otherfaction.h>
|
|
|
|
|
|
2007-02-03 15:09:03 +01:00
|
|
|
|
/* in spy steht der Unterschied zwischen Wahrnehmung des Opfers und
|
2007-07-17 17:33:48 +02:00
|
|
|
|
* Spionage des Spions */
|
2007-02-03 15:09:03 +01:00
|
|
|
|
void
|
|
|
|
|
spy_message(int spy, const unit *u, const unit *target)
|
|
|
|
|
{
|
2007-08-10 09:03:23 +02:00
|
|
|
|
const char * str = report_kampfstatus(target, u->faction->locale);
|
2007-08-08 09:43:24 +02:00
|
|
|
|
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u, target, str));
|
|
|
|
|
if (spy > 20) {
|
2007-02-03 15:09:03 +01:00
|
|
|
|
sc_mage * m = get_mage(target);
|
2007-07-17 17:33:48 +02:00
|
|
|
|
/* bei Magiern Zauberspr<70>che und Magiegebiet */
|
|
|
|
|
if (m) {
|
2007-08-08 09:43:24 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", target, magietypen[find_magetype(target)]));
|
2007-07-17 17:33:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-08-08 09:43:24 +02:00
|
|
|
|
if (spy > 6) {
|
|
|
|
|
faction * fv = visible_faction(u->faction,target);
|
|
|
|
|
if (fv && fv!=target->faction) {
|
|
|
|
|
/* wahre Partei */
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", "target faction", target, target->faction));
|
2007-07-17 17:33:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-08-08 09:43:24 +02:00
|
|
|
|
if (spy > 0) {
|
2007-02-03 15:09:03 +01:00
|
|
|
|
int first = 1;
|
|
|
|
|
int found = 0;
|
|
|
|
|
skill * sv;
|
2007-08-08 09:43:24 +02:00
|
|
|
|
char buf[4096];
|
2007-02-03 15:09:03 +01:00
|
|
|
|
|
2007-08-08 09:43:24 +02:00
|
|
|
|
buf[0] = 0;
|
2007-02-03 15:09:03 +01:00
|
|
|
|
for (sv = target->skills;sv!=target->skills+target->skill_size;++sv) {
|
|
|
|
|
if (sv->level>0) {
|
|
|
|
|
found++;
|
|
|
|
|
if (first == 1) {
|
|
|
|
|
first = 0;
|
|
|
|
|
} else {
|
2007-08-08 09:43:24 +02:00
|
|
|
|
strncat(buf, ", ", sizeof(buf));
|
2007-02-03 15:09:03 +01:00
|
|
|
|
}
|
2007-08-08 09:43:24 +02:00
|
|
|
|
strncat(buf, (const char *)skillname(sv->id, u->faction->locale), sizeof(buf));
|
|
|
|
|
strncat(buf, " ", sizeof(buf));
|
|
|
|
|
strncat(buf, itoa10(eff_skill(target, sv->id, target->region)), sizeof(buf));
|
2007-02-03 15:09:03 +01:00
|
|
|
|
}
|
2007-02-04 14:55:06 +01:00
|
|
|
|
}
|
2007-08-08 09:43:24 +02:00
|
|
|
|
if (found) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", target, buf));
|
2007-02-04 14:55:06 +01:00
|
|
|
|
}
|
2007-07-17 17:33:48 +02:00
|
|
|
|
|
2007-08-08 09:43:24 +02:00
|
|
|
|
if (target->items) {
|
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", target, target->items));
|
2007-07-17 17:33:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-02-03 15:09:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
int
|
|
|
|
|
spy_cmd(unit * u, struct order * ord)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-10 12:43:46 +02:00
|
|
|
|
unit *target;
|
|
|
|
|
int spy, observe;
|
2004-02-09 23:20:40 +01:00
|
|
|
|
double spychance, observechance;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region * r = u->region;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
2004-04-10 12:43:46 +02:00
|
|
|
|
target = getunit(r, u->faction);
|
|
|
|
|
|
|
|
|
|
if (!target) {
|
2007-02-10 22:47:51 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", ""));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
return 0;
|
2004-04-10 12:43:46 +02:00
|
|
|
|
}
|
|
|
|
|
if (!can_contact(r, u, target)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 24, MSG_EVENT);
|
|
|
|
|
return 0;
|
2004-04-10 12:43:46 +02:00
|
|
|
|
}
|
|
|
|
|
if (eff_skill(u, SK_SPY, r) < 1) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 39, MSG_EVENT);
|
|
|
|
|
return 0;
|
2004-04-10 12:43:46 +02:00
|
|
|
|
}
|
|
|
|
|
/* Die Grundchance f<>r einen erfolgreichen Spionage-Versuch ist 10%.
|
|
|
|
|
* F<EFBFBD>r jeden Talentpunkt, den das Spionagetalent das Tarnungstalent
|
|
|
|
|
* des Opfers <EFBFBD>bersteigt, erh<EFBFBD>ht sich dieses um 5%*/
|
|
|
|
|
spy = eff_skill(u, SK_SPY, r) - eff_skill(target, SK_STEALTH, r);
|
|
|
|
|
spychance = 0.1 + max(spy*0.05, 0.0);
|
|
|
|
|
|
|
|
|
|
if (chance(spychance)) {
|
2007-02-03 15:09:03 +01:00
|
|
|
|
produceexp(u, SK_SPY, u->number);
|
2004-04-10 12:43:46 +02:00
|
|
|
|
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
|
|
|
|
|
* Wahrnehmung als das Ziel Tarnung + Spionage/2 hat */
|
|
|
|
|
observe = eff_skill(target, SK_OBSERVATION, r)
|
|
|
|
|
- (effskill(u, SK_STEALTH) + eff_skill(u, SK_SPY, r)/2);
|
2002-11-27 20:35:36 +01:00
|
|
|
|
|
2005-07-10 18:32:47 +02:00
|
|
|
|
if (invisible(u, target) >= u->number) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
observe = min(observe, 0);
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
/* Anschlie<69>end wird - unabh<62>ngig vom Erfolg - gew<65>rfelt, ob der
|
|
|
|
|
* Spionageversuch bemerkt wurde. Die Wahrscheinlich daf<EFBFBD>r ist (100 -
|
|
|
|
|
* SpionageSpion*5 + WahrnehmungOpfer*2)%. */
|
|
|
|
|
observechance = 1.0 - (eff_skill(u, SK_SPY, r) * 0.05)
|
|
|
|
|
+ (eff_skill(target, SK_OBSERVATION, r) * 0.02);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2006-01-08 12:33:10 +01:00
|
|
|
|
if (chance(observechance)) {
|
|
|
|
|
ADDMSG(&target->faction->msgs, msg_message("spydetect",
|
|
|
|
|
"spy target", observe>0?u:NULL, target));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
int
|
|
|
|
|
setwere_cmd(unit *u, struct order * ord)
|
2002-04-12 14:46:16 +02:00
|
|
|
|
{
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#ifdef KARMA_MODULE
|
2004-06-21 18:45:27 +02:00
|
|
|
|
int level = fspecial(u->faction, FS_LYCANTROPE);
|
|
|
|
|
const char *s;
|
2002-04-12 14:46:16 +02:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (!level) {
|
|
|
|
|
cmistake(u, ord, 311, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2002-04-12 14:46:16 +02:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
|
|
|
|
|
if (s == NULL || *s == '\0') {
|
|
|
|
|
if(fval(u, UFL_WERE)) {
|
|
|
|
|
cmistake(u, ord, 309, MSG_EVENT);
|
2006-02-19 23:43:56 +01:00
|
|
|
|
} else if(rng_int()%100 < 35+(level-1)*20) { /* 35, 55, 75, 95% */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
fset(u, UFL_WERE);
|
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, ord, 311, MSG_EVENT);
|
|
|
|
|
}
|
|
|
|
|
} else if (findparam(s, u->faction->locale) == P_NOT) {
|
|
|
|
|
if(fval(u, UFL_WERE)) {
|
|
|
|
|
cmistake(u, ord, 310, MSG_EVENT);
|
2006-02-19 23:43:56 +01:00
|
|
|
|
} else if(rng_int()%100 < 90-level*20) { /* 70, 50, 30, 10% */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
freset(u, UFL_WERE);
|
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, ord, 311, MSG_EVENT);
|
|
|
|
|
}
|
2002-04-12 14:46:16 +02:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#endif /* KARMA_MODULE */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
return 0;
|
2002-04-12 14:46:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
int
|
|
|
|
|
setstealth_cmd(unit * u, struct order * ord)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2007-08-10 09:03:23 +02:00
|
|
|
|
const char *s;
|
2007-08-08 09:43:24 +02:00
|
|
|
|
int level;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
const race * trace;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
s = getstrtoken();
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
/* Tarne ohne Parameter: Setzt maximale Tarnung */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (s == NULL || *s == 0) {
|
|
|
|
|
u_seteffstealth(u, -1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
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]) {
|
|
|
|
|
race_t allowed[] = { RC_DWARF, RC_ELF, RC_ORC, RC_GOBLIN, RC_HUMAN,
|
|
|
|
|
RC_TROLL, RC_DAEMON, RC_INSECT, RC_HALFLING, RC_CAT, RC_AQUARIAN,
|
|
|
|
|
RC_URUK, NORACE };
|
|
|
|
|
int i;
|
|
|
|
|
for (i=0;allowed[i]!=NORACE;++i) if (new_race[allowed[i]]==trace) break;
|
|
|
|
|
if (new_race[allowed[i]]==trace) {
|
|
|
|
|
u->irace = trace;
|
|
|
|
|
if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs))
|
|
|
|
|
set_racename(&u->attribs, NULL);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2005-10-23 11:05:11 +02:00
|
|
|
|
/* Singdrachen k<>nnen sich nur als Drachen tarnen */
|
|
|
|
|
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]) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
u->irace = trace;
|
|
|
|
|
if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs))
|
|
|
|
|
set_racename(&u->attribs, NULL);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
/* 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;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
switch(findparam(s, u->faction->locale)) {
|
|
|
|
|
case P_FACTION:
|
|
|
|
|
/* TARNE PARTEI [NICHT|NUMMER abcd] */
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
if(!s || *s == 0) {
|
|
|
|
|
fset(u, UFL_PARTEITARNUNG);
|
|
|
|
|
} else if (findparam(s, u->faction->locale) == P_NOT) {
|
|
|
|
|
freset(u, UFL_PARTEITARNUNG);
|
|
|
|
|
} else if (findkeyword(s, u->faction->locale) == K_NUMBER) {
|
2007-08-08 09:43:24 +02:00
|
|
|
|
const char *s2 = (const char *)getstrtoken();
|
2004-06-21 18:45:27 +02:00
|
|
|
|
int nr = -1;
|
|
|
|
|
|
2007-07-23 21:36:43 +02:00
|
|
|
|
if (s2) nr = atoi36(s2);
|
|
|
|
|
if (!s2 || *s2 == 0 || nr == u->faction->no) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
a_removeall(&u->attribs, &at_otherfaction);
|
|
|
|
|
} else {
|
|
|
|
|
struct faction * f = findfaction(nr);
|
|
|
|
|
if(f==NULL) {
|
|
|
|
|
cmistake(u, ord, 66, MSG_EVENT);
|
|
|
|
|
} else {
|
2004-12-03 20:08:00 +01:00
|
|
|
|
region * lastr = NULL;
|
|
|
|
|
/* for all units mu of our faction, check all the units in the region
|
2007-07-17 17:33:48 +02: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. */
|
2004-12-03 20:08:00 +01:00
|
|
|
|
unit * mu = u->faction->units;
|
|
|
|
|
while (mu!=NULL) {
|
|
|
|
|
unit * ru = mu->region->units;
|
2004-12-14 01:23:19 +01:00
|
|
|
|
if (mu->region!=lastr) {
|
2005-01-03 22:28:21 +01:00
|
|
|
|
lastr = mu->region;
|
2004-12-14 01:23:19 +01:00
|
|
|
|
while (ru!=NULL) {
|
2005-01-03 22:28:21 +01:00
|
|
|
|
faction * fv = visible_faction(f, ru);
|
|
|
|
|
if (fv==f) {
|
|
|
|
|
if (cansee(f, lastr, ru, 0)) break;
|
2004-12-14 01:23:19 +01:00
|
|
|
|
}
|
|
|
|
|
ru = ru->next;
|
2004-12-03 20:08:00 +01:00
|
|
|
|
}
|
2004-12-14 01:23:19 +01:00
|
|
|
|
if (ru!=NULL) break;
|
2004-12-03 20:08:00 +01:00
|
|
|
|
}
|
|
|
|
|
mu = mu->nextF;
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, ord, 289, MSG_EVENT);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case P_ANY:
|
|
|
|
|
/* TARNE ALLES (was nicht so alles geht?) */
|
|
|
|
|
u_seteffstealth(u, -1);
|
|
|
|
|
break;
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#ifdef KARMA_MODULE
|
2004-06-21 18:45:27 +02:00
|
|
|
|
case P_NUMBER:
|
|
|
|
|
/* TARNE ANZAHL [NICHT] */
|
2006-02-17 23:59:03 +01:00
|
|
|
|
if (!fspecial(u->faction, FS_HIDDEN)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, ord, 277, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
if (findparam(s, u->faction->locale) == P_NOT) {
|
2006-02-17 23:59:03 +01:00
|
|
|
|
attrib * a = a_find(u->attribs, &at_fshidden);
|
|
|
|
|
if (a==NULL) a->data.ca[0] = 0;
|
|
|
|
|
if (a->data.i == 0) a_remove(&u->attribs, a);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
} else {
|
2006-02-17 23:59:03 +01:00
|
|
|
|
attrib * a = a_find(u->attribs, &at_fshidden);
|
|
|
|
|
if (a!=NULL) a = a_add(&u->attribs, a_new(&at_fshidden));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
a->data.ca[0] = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#endif /* KARMA_MODULE */
|
|
|
|
|
#ifdef KARMA_MODULE
|
2004-06-21 18:45:27 +02:00
|
|
|
|
case P_ITEMS:
|
|
|
|
|
/* TARNE GEGENST<53>NDE [NICHT] */
|
|
|
|
|
if(!fspecial(u->faction, FS_HIDDEN)) {
|
|
|
|
|
cmistake(u, ord, 277, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (findparam(s, u->faction->locale) == P_NOT) {
|
2006-02-17 23:59:03 +01:00
|
|
|
|
attrib * a = a_find(u->attribs, &at_fshidden);
|
|
|
|
|
if (a!=NULL) a->data.ca[1] = 0;
|
|
|
|
|
if (a->data.i == 0) a_remove(&u->attribs, a);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
} else {
|
2006-02-17 23:59:03 +01:00
|
|
|
|
attrib * a = a_find(u->attribs, &at_fshidden);
|
|
|
|
|
if (a==NULL) a = a_add(&u->attribs, a_new(&at_fshidden));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
a->data.ca[1] = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2006-02-17 23:59:03 +01:00
|
|
|
|
#endif /* KARMA_MODULE */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
case P_NOT:
|
|
|
|
|
u_seteffstealth(u, -1);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (isdigit(s[0])) {
|
|
|
|
|
/* Tarnungslevel setzen */
|
2007-08-08 09:43:24 +02:00
|
|
|
|
level = atoi((const char *)s);
|
2004-06-21 18:45:27 +02:00
|
|
|
|
if (level > effskill(u, SK_STEALTH)) {
|
2007-07-23 21:36:43 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", ""));
|
2004-06-21 18:45:27 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
u_seteffstealth(u, level);
|
|
|
|
|
} else if (u->race->flags & RCF_SHAPESHIFTANY) {
|
|
|
|
|
set_racename(&u->attribs, s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2002-02-15 17:13:30 +01:00
|
|
|
|
faction_skill(region * r, faction * f, skill_t sk)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2007-07-17 17:33:48 +02:00
|
|
|
|
int value = 0;
|
|
|
|
|
unit *u;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2007-06-20 02:34:02 +02:00
|
|
|
|
for (u=r->units; u; u=u->next) {
|
2007-07-17 17:33:48 +02:00
|
|
|
|
if (u->faction == f) {
|
|
|
|
|
int s = eff_skill(u, sk, r);
|
|
|
|
|
value = max(value, s);
|
|
|
|
|
}
|
2007-06-20 02:34:02 +02:00
|
|
|
|
}
|
2007-07-17 17:33:48 +02:00
|
|
|
|
return value;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2002-02-15 17:13:30 +01:00
|
|
|
|
crew_skill(region * r, faction * f, ship * sh, skill_t sk)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2007-07-17 17:33:48 +02:00
|
|
|
|
int value = 0;
|
|
|
|
|
unit *u;
|
|
|
|
|
|
|
|
|
|
for (u=r->units;u;u=u->next) {
|
|
|
|
|
if (u->ship == sh && u->faction == f) {
|
|
|
|
|
int s = eff_skill(u, sk, r);
|
|
|
|
|
value = max(s, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return value;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2007-07-23 21:36:43 +02:00
|
|
|
|
try_destruction(unit * u, unit * u2, const ship *sh, int skilldiff)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2007-07-23 21:36:43 +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";
|
2007-02-04 14:30:06 +01:00
|
|
|
|
|
|
|
|
|
if (skilldiff == 0) {
|
|
|
|
|
/* tell the unit that the attempt failed: */
|
2007-07-23 21:36:43 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message(destruction_failed_msg, "ship unit", sh, u));
|
2007-02-04 14:30:06 +01:00
|
|
|
|
/* tell the enemy about the attempt: */
|
|
|
|
|
if (u2) {
|
2007-07-23 21:36:43 +02:00
|
|
|
|
ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh));
|
2007-02-04 14:30:06 +01:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
2007-07-23 21:36:43 +02:00
|
|
|
|
} else if (skilldiff < 0) {
|
2007-02-04 14:30:06 +01:00
|
|
|
|
/* tell the unit that the attempt was detected: */
|
2007-07-23 21:36:43 +02:00
|
|
|
|
ADDMSG(&u2->faction->msgs, msg_message(destruction_detected_msg, "ship unit", sh, u));
|
2007-02-04 14:30:06 +01:00
|
|
|
|
/* tell the enemy whodunit: */
|
|
|
|
|
if (u2) {
|
2007-12-19 22:49:19 +01:00
|
|
|
|
ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh));
|
2007-02-04 14:30:06 +01:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
2007-07-23 21:36:43 +02:00
|
|
|
|
} else {
|
2007-02-04 14:30:06 +01:00
|
|
|
|
/* tell the unit that the attempt succeeded */
|
2007-07-23 21:36:43 +02:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message(destruction_success_msg, "ship unit", sh, u));
|
|
|
|
|
if (u2) {
|
|
|
|
|
ADDMSG(&u2->faction->msgs, msg_message(object_destroyed_msg, "ship", sh));
|
|
|
|
|
}
|
2007-02-04 14:30:06 +01:00
|
|
|
|
}
|
|
|
|
|
return 1; /* success */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sink_ship(region * r, ship * sh, const char *name, char spy, unit * saboteur)
|
|
|
|
|
{
|
2007-07-17 17:33:48 +02:00
|
|
|
|
unit **ui;
|
|
|
|
|
region *safety = r;
|
|
|
|
|
int i;
|
|
|
|
|
direction_t d;
|
|
|
|
|
unsigned int index;
|
|
|
|
|
double probability = 0.0;
|
|
|
|
|
vset informed;
|
|
|
|
|
vset survivors;
|
2007-07-23 21:36:43 +02:00
|
|
|
|
message * sink_msg = NULL;
|
|
|
|
|
message * enemy_discovers_spy_msg = NULL;
|
2007-07-17 17:33:48 +02:00
|
|
|
|
|
|
|
|
|
vset_init(&informed);
|
|
|
|
|
vset_init(&survivors);
|
|
|
|
|
|
|
|
|
|
/* figure out what a unit's chances of survival are: */
|
2005-10-25 14:38:01 +02:00
|
|
|
|
if (!fval(r->terrain, SEA_REGION)) {
|
|
|
|
|
probability = CANAL_SWIMMER_CHANCE;
|
|
|
|
|
} else {
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
|
|
|
|
region * rn = rconnect(r, d);
|
|
|
|
|
if (!fval(rn->terrain, SEA_REGION) && !move_blocked(NULL, r, rn)) {
|
|
|
|
|
safety = rn;
|
|
|
|
|
probability = OCEAN_SWIMMER_CHANCE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-07-17 17:33:48 +02:00
|
|
|
|
for (ui = &r->units; *ui; ui = &(*ui)->next) {
|
|
|
|
|
unit *u = *ui;
|
|
|
|
|
|
|
|
|
|
/* inform this faction about the sinking ship: */
|
|
|
|
|
vset_add(&informed, u->faction);
|
|
|
|
|
if (u->ship == sh) {
|
|
|
|
|
int dead = 0;
|
2007-07-23 21:36:43 +02:00
|
|
|
|
message * msg;
|
2007-07-17 17:33:48 +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 */
|
|
|
|
|
{
|
|
|
|
|
vset_add(&survivors, u);
|
|
|
|
|
if (dead > 0) {
|
2007-07-23 21:36:43 +02:00
|
|
|
|
msg = msg_message("sink_lost_msg", "dead region unit", dead, safety, u);
|
|
|
|
|
} else {
|
|
|
|
|
msg = msg_message("sink_saved_msg", "region unit", safety, u);
|
|
|
|
|
}
|
2007-07-17 17:33:48 +02:00
|
|
|
|
set_leftship(u, u->ship);
|
|
|
|
|
u->ship = 0;
|
2007-07-23 21:36:43 +02:00
|
|
|
|
if (r != safety) {
|
2007-07-17 17:33:48 +02:00
|
|
|
|
setguard(u, GUARD_NONE);
|
2007-07-23 21:36:43 +02:00
|
|
|
|
}
|
|
|
|
|
while (u->items) {
|
|
|
|
|
i_remove(&u->items, u->items);
|
|
|
|
|
}
|
2007-07-17 17:33:48 +02:00
|
|
|
|
move_unit(u, safety, NULL);
|
|
|
|
|
} else {
|
2007-07-23 21:36:43 +02:00
|
|
|
|
msg = msg_message("sink_lost_msg", "dead region unit", dead, NULL, u);
|
2007-07-17 17:33:48 +02:00
|
|
|
|
}
|
2007-07-23 21:36:43 +02:00
|
|
|
|
add_message(&u->faction->msgs, msg);
|
|
|
|
|
msg_release(msg);
|
2007-07-17 17:33:48 +02:00
|
|
|
|
if (dead == u->number) {
|
2006-08-12 21:15:16 +02:00
|
|
|
|
/* the poor creature, she dies */
|
2007-07-17 17:33:48 +02:00
|
|
|
|
*ui = u->next;
|
|
|
|
|
destroy_unit(u);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* inform everyone, and reduce money to the absolutely necessary
|
|
|
|
|
* amount: */
|
|
|
|
|
while (informed.size != 0) {
|
|
|
|
|
unit *lastunit = 0;
|
2005-11-25 23:09:59 +01:00
|
|
|
|
int money = 0, maintain = 0;
|
2007-07-17 17:33:48 +02:00
|
|
|
|
faction * f = (faction *) informed.data[0];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-11-25 23:09:59 +01:00
|
|
|
|
/* find out how much money this faction still has: */
|
2007-07-17 17:33:48 +02:00
|
|
|
|
for (index = 0; index != survivors.size; ++index) {
|
|
|
|
|
unit *u = (unit *) survivors.data[index];
|
|
|
|
|
|
|
|
|
|
if (u->faction == f) {
|
|
|
|
|
maintain += maintenance_cost(u);
|
|
|
|
|
money += get_money(u);
|
|
|
|
|
lastunit = u;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* 'money' shall be the maintenance-surplus of the survivng
|
|
|
|
|
* units: */
|
|
|
|
|
money = money - maintain;
|
|
|
|
|
for (index = 0; money > 0; ++index) {
|
|
|
|
|
int remove;
|
|
|
|
|
unit *u = (unit *) survivors.data[index];
|
|
|
|
|
|
|
|
|
|
assert(index < survivors.size);
|
|
|
|
|
if (u->faction == f && playerrace(u->race)) {
|
|
|
|
|
remove = min(get_money(u), money);
|
|
|
|
|
money -= remove;
|
|
|
|
|
change_money(u, -remove);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* finally, report to this faction that the ship sank: */
|
2007-07-23 21:36:43 +02:00
|
|
|
|
if (sink_msg==NULL) {
|
|
|
|
|
sink_msg = msg_message("sink_msg", "ship region", sh, r);
|
|
|
|
|
}
|
|
|
|
|
add_message(&f->msgs, sink_msg);
|
2007-07-17 17:33:48 +02:00
|
|
|
|
vset_erase(&informed, f);
|
2007-07-23 21:36:43 +02:00
|
|
|
|
if (spy == 1 && f != saboteur->faction && faction_skill(r, f, SK_OBSERVATION) - eff_skill(saboteur, SK_STEALTH, r) > 0) {
|
|
|
|
|
/* the unit is discovered */
|
|
|
|
|
ADDMSG(&f->msgs, msg_message("spy_discovered_msg", "unit saboteur ship", lastunit, saboteur, sh));
|
|
|
|
|
if (enemy_discovers_spy_msg==NULL) {
|
|
|
|
|
enemy_discovers_spy_msg = msg_message("enemy_discovers_spy_msg", "unit ship", saboteur, sh);
|
|
|
|
|
}
|
|
|
|
|
add_message(&saboteur->faction->msgs, sink_msg);
|
2007-07-17 17:33:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-07-23 21:36:43 +02:00
|
|
|
|
if (enemy_discovers_spy_msg) msg_release(enemy_discovers_spy_msg);
|
|
|
|
|
if (sink_msg) msg_release(sink_msg);
|
2007-07-17 17:33:48 +02:00
|
|
|
|
/* finally, get rid of the ship */
|
|
|
|
|
destroy_ship(sh);
|
|
|
|
|
vset_destroy(&informed);
|
|
|
|
|
vset_destroy(&survivors);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
int
|
|
|
|
|
sabotage_cmd(unit * u, struct order * ord)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2007-08-10 09:03:23 +02:00
|
|
|
|
const char *s;
|
2007-07-17 17:33:48 +02:00
|
|
|
|
int i;
|
|
|
|
|
ship *sh;
|
|
|
|
|
unit *u2;
|
|
|
|
|
char buffer[DISPLAYSIZE];
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region * r = u->region;
|
2007-07-23 21:36:43 +02:00
|
|
|
|
int skdiff;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
2007-07-17 17:33:48 +02:00
|
|
|
|
s = getstrtoken();
|
|
|
|
|
|
|
|
|
|
i = findparam(s, u->faction->locale);
|
|
|
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
|
case P_SHIP:
|
|
|
|
|
sh = u->ship;
|
|
|
|
|
if (!sh) {
|
|
|
|
|
cmistake(u, u->thisorder, 144, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
u2 = shipowner(sh);
|
2007-07-23 21:36:43 +02:00
|
|
|
|
skdiff = eff_skill(u, SK_SPY, r)-crew_skill(r, u2->faction, sh, SK_OBSERVATION);
|
|
|
|
|
if (try_destruction(u, u2, sh, skdiff)) {
|
2007-07-17 17:33:48 +02:00
|
|
|
|
sink_ship(r, sh, buffer, 1, u);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cmistake(u, u->thisorder, 9, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-01-31 18:40:53 +01:00
|
|
|
|
|