2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
2001-12-10 01:13:39 +01:00
|
|
|
|
*
|
2003-07-29 11:48:03 +02:00
|
|
|
|
* Eressea PB(E)M host Copyright (C) 1998-2003
|
2001-01-25 10:37:55 +01:00
|
|
|
|
* Christian Schlittchen (corwin@amber.kn-bremen.de)
|
|
|
|
|
* Katja Zedel (katze@felidae.kn-bremen.de)
|
|
|
|
|
* Henning Peters (faroul@beyond.kn-bremen.de)
|
|
|
|
|
* Enno Rehling (enno@eressea-pbem.de)
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "eressea.h"
|
|
|
|
|
#include "spy.h"
|
|
|
|
|
|
|
|
|
|
/* kernel includes */
|
|
|
|
|
#include "build.h"
|
|
|
|
|
#include "economy.h"
|
|
|
|
|
#include "item.h"
|
|
|
|
|
#include "karma.h"
|
|
|
|
|
#include "faction.h"
|
|
|
|
|
#include "magic.h"
|
|
|
|
|
#include "message.h"
|
|
|
|
|
#include "movement.h"
|
|
|
|
|
#include "race.h"
|
|
|
|
|
#include "region.h"
|
|
|
|
|
#include "ship.h"
|
|
|
|
|
#include "skill.h"
|
|
|
|
|
#include "unit.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
|
|
|
|
/* attributes includes */
|
|
|
|
|
#include <attributes/racename.h>
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* util includes */
|
2004-02-09 23:20:40 +01:00
|
|
|
|
#include <util/vset.h>
|
|
|
|
|
#include <util/rand.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>
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
|
|
|
|
spy(region * r, unit * u)
|
|
|
|
|
{
|
|
|
|
|
unit *target;
|
2004-02-09 23:20:40 +01:00
|
|
|
|
int spy, observe;
|
|
|
|
|
double spychance, observechance;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-04-26 19:41:06 +02:00
|
|
|
|
target = getunit(r, u->faction);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (!target) {
|
2003-03-08 21:57:38 +01:00
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 63, MSG_EVENT);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!can_contact(r, u, target)) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 24, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (eff_skill(u, SK_SPY, r) < 1) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 39, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01: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);
|
2004-02-09 23:20:40 +01:00
|
|
|
|
spychance = 0.1 + max(spy*0.05, 0.0);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-09 23:20:40 +01:00
|
|
|
|
if (chance(spychance)) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
spy_message(spy, u, target);
|
|
|
|
|
} else {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"spyfail%u:spy%u:target", u, target));
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* 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
|
|
|
|
|
|
|
|
|
#if NEWATSROI == 0
|
2002-05-05 18:59:25 +02:00
|
|
|
|
if (invisible(u) >= u->number &&
|
2001-01-25 10:37:55 +01:00
|
|
|
|
get_item(target, I_AMULET_OF_TRUE_SEEING) == 0) {
|
|
|
|
|
observe = min(observe, 0);
|
|
|
|
|
}
|
2002-11-27 20:35:36 +01:00
|
|
|
|
#endif
|
2001-12-10 01:13:39 +01: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)%. */
|
2004-02-09 23:20:40 +01:00
|
|
|
|
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
|
|
|
|
|
2004-02-09 23:20:40 +01:00
|
|
|
|
if (chance(observechance)){
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&target->faction->msgs, new_message(target->faction,
|
|
|
|
|
"spydetect%u:spy%u:target", observe>0?u:NULL, target));
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-04-12 14:46:16 +02:00
|
|
|
|
void
|
|
|
|
|
setwere(unit *u, strlist *S)
|
|
|
|
|
{
|
|
|
|
|
int level = fspecial(u->faction,FS_LYCANTROPE);
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s;
|
2002-04-12 14:46:16 +02:00
|
|
|
|
|
|
|
|
|
if(!level) {
|
|
|
|
|
cmistake(u, S->s, 311, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
|
|
|
|
|
if(s == NULL || *s == '\0') {
|
|
|
|
|
if(fval(u, UFL_WERE)) {
|
|
|
|
|
cmistake(u, S->s, 309, MSG_EVENT);
|
|
|
|
|
} else if(rand()%100 < 35+(level-1)*20) { /* 35, 55, 75, 95% */
|
|
|
|
|
fset(u, UFL_WERE);
|
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, S->s, 311, MSG_EVENT);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(findparam(s, u->faction->locale) == P_NOT) {
|
|
|
|
|
if(fval(u, UFL_WERE)) {
|
|
|
|
|
cmistake(u, S->s, 310, MSG_EVENT);
|
|
|
|
|
} else if(rand()%100 < 90-level*20) { /* 70, 50, 30, 10% */
|
|
|
|
|
freset(u, UFL_WERE);
|
|
|
|
|
} else {
|
|
|
|
|
cmistake(u, S->s, 311, MSG_EVENT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
|
|
|
|
setstealth(unit * u, strlist * S)
|
|
|
|
|
{
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
char level;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
const race * trace;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
attrib *a;
|
|
|
|
|
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
|
|
|
|
|
/* Tarne ohne Parameter: Setzt maximale Tarnung */
|
|
|
|
|
|
2001-02-07 21:42:31 +01:00
|
|
|
|
if (s == NULL || *s == 0) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
u_seteffstealth(u, -1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01: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,
|
2002-02-10 17:04:39 +01:00
|
|
|
|
RC_TROLL, RC_DAEMON, RC_INSECT, RC_HALFLING, RC_CAT, RC_AQUARIAN,
|
|
|
|
|
RC_URUK, NORACE };
|
2001-12-10 01:13:39 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pseudodrachen k<>nnen sich nur als Drachen tarnen */
|
|
|
|
|
if (u->race == new_race[RC_PSEUDODRAGON] || u->race == new_race[RC_BIRTHDAYDRAGON]) {
|
|
|
|
|
if (trace==new_race[RC_PSEUDODRAGON]||trace==new_race[RC_FIREDRAGON]||trace==new_race[RC_DRAGON]||trace==new_race[RC_WYRM]) {
|
|
|
|
|
u->irace = trace;
|
|
|
|
|
if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs))
|
- 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
|
|
|
|
set_racename(&u->attribs, NULL);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-01 08:58:45 +02:00
|
|
|
|
/* D<>momen und Illusionsparteien k<>nnen sich als andere race tarnen */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race->flags & RCF_SHAPESHIFT) {
|
|
|
|
|
if (playerrace(trace)) {
|
|
|
|
|
u->irace = trace;
|
2002-05-11 20:22:22 +02:00
|
|
|
|
if ((u->race->flags & RCF_SHAPESHIFTANY) && get_racename(u->attribs))
|
- 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
|
|
|
|
set_racename(&u->attribs, NULL);
|
2001-04-01 08:58:45 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-04-01 08:58:45 +02:00
|
|
|
|
return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
switch(findparam(s, u->faction->locale)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case P_FACTION:
|
2001-04-14 14:11:45 +02:00
|
|
|
|
/* TARNE PARTEI [NICHT|NUMMER abcd] */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
s = getstrtoken();
|
2001-04-14 14:11:45 +02:00
|
|
|
|
if(!s || *s == 0) {
|
2003-07-29 11:48:03 +02:00
|
|
|
|
fset(u, UFL_PARTEITARNUNG);
|
2001-04-16 16:34:19 +02:00
|
|
|
|
} else if (findparam(s, u->faction->locale) == P_NOT) {
|
2003-07-29 11:48:03 +02:00
|
|
|
|
freset(u, UFL_PARTEITARNUNG);
|
2001-04-16 16:34:19 +02:00
|
|
|
|
} else if (findkeyword(s, u->faction->locale) == K_NUMBER) {
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s2 = getstrtoken();
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int nr = -1;
|
|
|
|
|
|
|
|
|
|
if(s2) nr = atoi36(s2);
|
2001-04-22 20:14:07 +02:00
|
|
|
|
if(!s2 || *s2 == 0 || nr == u->faction->no) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
a_removeall(&u->attribs, &at_otherfaction);
|
2001-04-14 14:11:45 +02:00
|
|
|
|
} else {
|
2002-03-24 10:40:50 +01:00
|
|
|
|
struct faction * f = findfaction(nr);
|
2001-04-14 14:11:45 +02:00
|
|
|
|
/* TODO: Pr<50>fung ob Partei sichtbar */
|
2002-03-24 10:40:50 +01:00
|
|
|
|
if(f==NULL) {
|
2001-04-14 14:11:45 +02:00
|
|
|
|
cmistake(u, S->s, 66, MSG_EVENT);
|
|
|
|
|
} else {
|
|
|
|
|
attrib *a;
|
|
|
|
|
a = a_find(u->attribs, &at_otherfaction);
|
2002-03-24 10:40:50 +01:00
|
|
|
|
if (!a) a = a_add(&u->attribs, make_otherfaction(f));
|
|
|
|
|
else a->data.v = f;
|
2001-04-14 14:11:45 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
2001-04-14 14:11:45 +02:00
|
|
|
|
cmistake(u, S->s, 289, MSG_EVENT);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case P_ANY:
|
|
|
|
|
/* TARNE ALLES (was nicht so alles geht?) */
|
|
|
|
|
u_seteffstealth(u, -1);
|
|
|
|
|
break;
|
|
|
|
|
case P_NUMBER:
|
|
|
|
|
/* TARNE ANZAHL [NICHT] */
|
|
|
|
|
if(!fspecial(u->faction, FS_HIDDEN)) {
|
|
|
|
|
cmistake(u, S->s, 277, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
s = getstrtoken();
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (findparam(s, u->faction->locale) == P_NOT) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a = a_find(u->attribs, &at_fshidden);
|
|
|
|
|
if(a) a->data.ca[0] = 0;
|
|
|
|
|
if(a->data.i == 0) a_remove(&u->attribs, a);
|
|
|
|
|
} else {
|
|
|
|
|
a = a_find(u->attribs, &at_fshidden);
|
|
|
|
|
if(!a) a = a_add(&u->attribs, a_new(&at_fshidden));
|
|
|
|
|
a->data.ca[0] = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case P_ITEMS:
|
|
|
|
|
/* TARNE GEGENST<53>NDE [NICHT] */
|
|
|
|
|
if(!fspecial(u->faction, FS_HIDDEN)) {
|
|
|
|
|
cmistake(u, S->s, 277, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (findparam(s, u->faction->locale) == P_NOT) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
a = a_find(u->attribs, &at_fshidden);
|
|
|
|
|
if(a) a->data.ca[1] = 0;
|
|
|
|
|
if(a->data.i == 0) a_remove(&u->attribs, a);
|
|
|
|
|
} else {
|
|
|
|
|
a = a_find(u->attribs, &at_fshidden);
|
|
|
|
|
if(!a) a = a_add(&u->attribs, a_new(&at_fshidden));
|
|
|
|
|
a->data.ca[1] = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-03-31 10:54:33 +02:00
|
|
|
|
case P_NOT:
|
|
|
|
|
u_seteffstealth(u, -1);
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
default:
|
- 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
|
|
|
|
if (isdigit(s[0])) {
|
|
|
|
|
/* Tarnungslevel setzen */
|
|
|
|
|
level = (char) atoip(s);
|
|
|
|
|
if (level > effskill(u, SK_STEALTH)) {
|
|
|
|
|
sprintf(buf, "%s kann sich nicht so gut tarnen.", unitname(u));
|
|
|
|
|
mistake(u, S->s, buf, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
u_seteffstealth(u, level);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
} else if (u->race->flags & RCF_SHAPESHIFTANY) {
|
- 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
|
|
|
|
set_racename(&u->attribs, s);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2002-02-15 17:13:30 +01:00
|
|
|
|
int value = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit *u;
|
|
|
|
|
|
|
|
|
|
list_foreach(unit, r->units, u)
|
|
|
|
|
if (u->faction == f)
|
|
|
|
|
{
|
2002-02-15 17:13:30 +01:00
|
|
|
|
int s = eff_skill(u, sk, r);
|
|
|
|
|
value = max(value, s);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
list_next(u);
|
2002-02-15 17:13:30 +01: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
|
|
|
|
{
|
2002-02-15 17:13:30 +01:00
|
|
|
|
int value = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit *u;
|
|
|
|
|
|
2002-02-15 17:13:30 +01:00
|
|
|
|
for (u=r->units;u;u=u->next) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (u->ship == sh && u->faction == f) {
|
2002-02-15 17:13:30 +01:00
|
|
|
|
int s = eff_skill(u, sk, r);
|
|
|
|
|
value = max(s, value);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
|
|
|
|
return value;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
try_destruction(unit * u, unit * u2, const char *name, int skilldiff)
|
|
|
|
|
{
|
|
|
|
|
const char *destruction_success_msg = "%s wurde von %s zerstoert.";
|
|
|
|
|
const char *destruction_failed_msg = "%s konnte %s nicht zerstoeren.";
|
|
|
|
|
const char *destruction_detected_msg = "%s wurde beim Versuch, %s zu zerstoeren, entdeckt.";
|
|
|
|
|
const char *detect_failure_msg = "Es wurde versucht, %s zu zerstoeren.";
|
|
|
|
|
const char *object_destroyed_msg = "%s wurde zerstoert.";
|
|
|
|
|
|
|
|
|
|
if (skilldiff == 0) {
|
|
|
|
|
/* tell the unit that the attempt failed: */
|
|
|
|
|
sprintf(buf, destruction_failed_msg, unitname(u), name);
|
|
|
|
|
addmessage(0, u->faction, buf, MSG_EVENT, ML_WARN);
|
|
|
|
|
/* tell the enemy about the attempt: */
|
|
|
|
|
sprintf(buf, detect_failure_msg, name);
|
|
|
|
|
addmessage(0, u2->faction, buf, MSG_EVENT, ML_IMPORTANT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (skilldiff < 0) {
|
|
|
|
|
/* tell the unit that the attempt was detected: */
|
|
|
|
|
sprintf(buf, destruction_detected_msg, unitname(u), name);
|
|
|
|
|
addmessage(0, u->faction, buf, MSG_EVENT, ML_WARN);
|
|
|
|
|
/* tell the enemy whodunit: */
|
|
|
|
|
sprintf(buf, detect_failure_msg, unitname(u2), unitname(u), name);
|
|
|
|
|
addmessage(0, u2->faction, buf, MSG_EVENT, ML_IMPORTANT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* tell the unit that the attempt succeeded */
|
|
|
|
|
sprintf(buf, destruction_success_msg, name, unitname(u));
|
|
|
|
|
addmessage(0, u->faction, buf, MSG_EVENT, ML_INFO);
|
|
|
|
|
sprintf(buf, object_destroyed_msg, name);
|
|
|
|
|
addmessage(0, u2->faction, buf, MSG_EVENT, ML_IMPORTANT);
|
|
|
|
|
return 1; /* success */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sink_ship(region * r, ship * sh, const char *name, char spy, unit * saboteur)
|
|
|
|
|
{
|
|
|
|
|
const char *person_lost_msg = "- %d Person von %s ertrinkt; %s.";
|
|
|
|
|
const char *persons_lost_msg = "- %d Personen von %s ertrinken; %s.";
|
|
|
|
|
const char *unit_dies_msg = "Die Einheit wird ausgeloescht";
|
|
|
|
|
const char *unit_lives_msg = "Die Einheit rettet sich nach ";
|
|
|
|
|
const char *unit_intact_msg = "%s ueberlebt unbeschadet und rettet sich nach %s.";
|
|
|
|
|
const char *ship_sinks_msg = "%s versinkt im Ozean.";
|
|
|
|
|
const char *enemy_discovers_spy_msg = "%s wurde beim versenken von %s entdeckt.";
|
|
|
|
|
const char *spy_discovered_msg = "%s entdeckte %s beim versenken von %s.";
|
|
|
|
|
unit **ui;
|
|
|
|
|
region *safety = r;
|
|
|
|
|
faction *f;
|
|
|
|
|
int i;
|
|
|
|
|
direction_t d;
|
|
|
|
|
unsigned int index;
|
2004-02-09 23:20:40 +01:00
|
|
|
|
double probability = 0.0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int money, count;
|
|
|
|
|
char buffer[DISPLAYSIZE + 1];
|
|
|
|
|
vset informed;
|
|
|
|
|
vset survivors;
|
|
|
|
|
|
|
|
|
|
vset_init(&informed);
|
|
|
|
|
vset_init(&survivors);
|
|
|
|
|
|
|
|
|
|
/* figure out what a unit's chances of survival are: */
|
|
|
|
|
if (rterrain(r) != T_OCEAN)
|
2004-02-09 23:20:40 +01:00
|
|
|
|
probability = CANAL_SWIMMER_CHANCE;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; ++d)
|
|
|
|
|
if (rterrain(rconnect(r, d)) != T_OCEAN && !move_blocked(NULL, r, d)) {
|
|
|
|
|
safety = rconnect(r, d);
|
2004-02-09 23:20:40 +01:00
|
|
|
|
probability = OCEAN_SWIMMER_CHANCE;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
/* if this fails, I misunderstood something: */
|
|
|
|
|
for (i = 0; i != u->number; ++i)
|
2004-02-09 23:20:40 +01:00
|
|
|
|
if (chance(probability))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
++dead;
|
|
|
|
|
|
|
|
|
|
if (dead != u->number)
|
|
|
|
|
/* she will live. but her items get stripped */
|
|
|
|
|
{
|
|
|
|
|
vset_add(&survivors, u);
|
|
|
|
|
if (dead > 0) {
|
|
|
|
|
strcat(strcpy(buffer, unit_lives_msg), regionid(safety));
|
|
|
|
|
sprintf(buf, (dead == 1) ? person_lost_msg : persons_lost_msg,
|
|
|
|
|
dead, unitname(u), buffer);
|
|
|
|
|
} else
|
|
|
|
|
sprintf(buf, unit_intact_msg, unitname(u), regionid(safety));
|
|
|
|
|
addmessage(0, u->faction, buf, MSG_EVENT, ML_WARN);
|
|
|
|
|
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 {
|
|
|
|
|
sprintf(buf, (dead == 1) ? person_lost_msg : persons_lost_msg,
|
|
|
|
|
dead, unitname(u), unit_dies_msg);
|
|
|
|
|
}
|
|
|
|
|
if (dead == u->number)
|
|
|
|
|
/* the poor creature, she dies */
|
|
|
|
|
{
|
|
|
|
|
*ui = u->next;
|
|
|
|
|
destroy_unit(u);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* inform everyone, and reduce money to the absolutely necessary
|
|
|
|
|
* amount: */
|
|
|
|
|
while (informed.size != 0) {
|
|
|
|
|
unit *lastunit = 0;
|
|
|
|
|
|
|
|
|
|
f = (faction *) informed.data[0];
|
|
|
|
|
money = 0;
|
|
|
|
|
count = 0;
|
|
|
|
|
/* find out how much money this faction still has: */
|
|
|
|
|
for (index = 0; index != survivors.size; ++index) {
|
|
|
|
|
unit *u = (unit *) survivors.data[index];
|
|
|
|
|
|
|
|
|
|
if (u->faction == f) {
|
|
|
|
|
count += u->number;
|
|
|
|
|
money += get_money(u);
|
|
|
|
|
lastunit = u;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* 'money' shall be the maintenance-surplus of the survivng
|
|
|
|
|
* units: */
|
|
|
|
|
money = money - count * MAINTENANCE;
|
|
|
|
|
for (index = 0; money > 0; ++index) {
|
|
|
|
|
int remove;
|
|
|
|
|
unit *u = (unit *) survivors.data[index];
|
|
|
|
|
|
|
|
|
|
assert(index < survivors.size);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->faction == f && playerrace(u->race)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
remove = min(get_money(u), money);
|
|
|
|
|
money -= remove;
|
|
|
|
|
change_money(u, -remove);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* finally, report to this faction that the ship sank: */
|
|
|
|
|
sprintf(buf, ship_sinks_msg, name);
|
|
|
|
|
addmessage(0, f, buf, MSG_EVENT, ML_WARN);
|
|
|
|
|
vset_erase(&informed, f);
|
|
|
|
|
if (spy == 1 && f != saboteur->faction &&
|
|
|
|
|
faction_skill(r, f, SK_OBSERVATION) - eff_skill(saboteur, SK_STEALTH, r) > 0) {
|
|
|
|
|
/* the unit is discovered */
|
|
|
|
|
sprintf(buf, spy_discovered_msg, lastunit, unitname(saboteur), name);
|
|
|
|
|
addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT);
|
|
|
|
|
sprintf(buf, enemy_discovers_spy_msg, unitname(saboteur), name);
|
|
|
|
|
addmessage(0, saboteur->faction, buf, MSG_EVENT, ML_MISTAKE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* finally, get rid of the ship */
|
|
|
|
|
destroy_ship(sh, r);
|
|
|
|
|
vset_destroy(&informed);
|
|
|
|
|
vset_destroy(&survivors);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
sabotage(region * r, unit * u)
|
|
|
|
|
{
|
2003-06-22 10:38:55 +02:00
|
|
|
|
const char *s;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int i;
|
|
|
|
|
ship *sh;
|
|
|
|
|
unit *u2;
|
|
|
|
|
char buffer[DISPLAYSIZE];
|
|
|
|
|
|
|
|
|
|
s = getstrtoken();
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
i = findparam(s, u->faction->locale);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
|
case P_SHIP:
|
|
|
|
|
sh = u->ship;
|
|
|
|
|
if (!sh) {
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 144, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
u2 = shipowner(r, sh);
|
|
|
|
|
strcat(strcpy(buffer, shipname(sh)), sh->type->name[0]);
|
|
|
|
|
if (try_destruction(u, u2, buffer, eff_skill(u, SK_SPY, r)
|
|
|
|
|
- crew_skill(r, u2->faction, sh, SK_OBSERVATION))) {
|
|
|
|
|
sink_ship(r, sh, buffer, 1, u);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cmistake(u, findorder(u, u->thisorder), 9, MSG_EVENT);
|
2001-01-31 18:40:53 +01:00
|
|
|
|
return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-01-31 18:40:53 +01:00
|
|
|
|
|
|
|
|
|
return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-01-31 18:40:53 +01:00
|
|
|
|
|