2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
2001-04-16 16:34:19 +02: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.
|
|
|
|
|
*/
|
|
|
|
|
|
- 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
|
|
|
|
#define TEACH_ALL 1
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#define TEACH_FRIENDS
|
- 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
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "eressea.h"
|
2005-01-19 22:57:37 +01:00
|
|
|
|
#include "study.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-10-25 14:38:01 +02:00
|
|
|
|
#include <kernel/alchemy.h>
|
|
|
|
|
#include <kernel/building.h>
|
|
|
|
|
#include <kernel/faction.h>
|
|
|
|
|
#include <kernel/item.h>
|
|
|
|
|
#include <kernel/karma.h>
|
|
|
|
|
#include <kernel/magic.h>
|
|
|
|
|
#include <kernel/message.h>
|
|
|
|
|
#include <kernel/movement.h>
|
|
|
|
|
#include <kernel/order.h>
|
|
|
|
|
#include <kernel/plane.h>
|
|
|
|
|
#include <kernel/pool.h>
|
|
|
|
|
#include <kernel/race.h>
|
|
|
|
|
#include <kernel/region.h>
|
|
|
|
|
#include <kernel/skill.h>
|
|
|
|
|
#include <kernel/terrain.h>
|
|
|
|
|
#include <kernel/unit.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* util includes */
|
2005-10-25 14:38:01 +02:00
|
|
|
|
#include <util/base36.h>
|
|
|
|
|
#include <util/rand.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* libc includes */
|
2004-05-24 15:22:43 +02:00
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <limits.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
2004-05-24 15:22:43 +02:00
|
|
|
|
#include <string.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#define TEACHNUMBER 10
|
|
|
|
|
|
|
|
|
|
static skill_t
|
2001-04-16 16:34:19 +02:00
|
|
|
|
getskill(const struct locale * lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
return findskill(getstrtoken(), lang);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static magic_t
|
|
|
|
|
findmagicskill(const char *s)
|
|
|
|
|
{
|
|
|
|
|
return (char) findstr(magietypen, s, MAXMAGIETYP);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
magic_t
|
|
|
|
|
getmagicskill(void)
|
|
|
|
|
{
|
|
|
|
|
return findmagicskill(getstrtoken());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Vertraute und Kr<4B>ten sind keine Migranten */
|
2001-02-11 10:42:58 +01:00
|
|
|
|
boolean
|
|
|
|
|
is_migrant(unit *u)
|
|
|
|
|
{
|
|
|
|
|
if (u->race == u->faction->race) return false;
|
|
|
|
|
|
|
|
|
|
if (is_familiar(u)) return false;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race == new_race[RC_TOAD]) return false;
|
2001-02-11 10:42:58 +01:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-20 08:48:34 +02:00
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
boolean
|
|
|
|
|
magic_lowskill(unit *u)
|
|
|
|
|
{
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race == new_race[RC_TOAD]) return true;
|
2001-05-20 08:48:34 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-11 10:42:58 +01:00
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2005-01-19 22:57:37 +01:00
|
|
|
|
int
|
|
|
|
|
study_cost(unit *u, skill_t talent)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int stufe, k = 50;
|
|
|
|
|
|
|
|
|
|
switch (talent) {
|
|
|
|
|
case SK_SPY:
|
|
|
|
|
return 100;
|
|
|
|
|
break;
|
|
|
|
|
case SK_TACTICS:
|
|
|
|
|
case SK_HERBALISM:
|
|
|
|
|
case SK_ALCHEMY:
|
|
|
|
|
return 200;
|
|
|
|
|
break;
|
|
|
|
|
case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */
|
|
|
|
|
/* 'Stufe' ist dabei die n<>chste zu erreichende Stufe */
|
2002-02-15 17:13:30 +01:00
|
|
|
|
stufe = 1 + get_level(u, SK_MAGIC);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return k*(1+((stufe+1)*stufe/2));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
2002-03-10 13:04:12 +01:00
|
|
|
|
static void
|
|
|
|
|
init_learning(struct attrib * a)
|
|
|
|
|
{
|
|
|
|
|
a->data.v = calloc(sizeof(teaching_info), 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
done_learning(struct attrib * a)
|
|
|
|
|
{
|
|
|
|
|
free(a->data.v);
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-19 22:57:37 +01:00
|
|
|
|
const attrib_type at_learning = {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"learning",
|
2002-03-10 13:04:12 +01:00
|
|
|
|
init_learning, done_learning, NULL, NULL, NULL,
|
2001-01-25 10:37:55 +01:00
|
|
|
|
ATF_UNIQUE
|
|
|
|
|
};
|
|
|
|
|
|
- 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
|
|
|
|
static int
|
2002-03-10 13:04:12 +01:00
|
|
|
|
teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk,
|
2002-02-15 17:13:30 +01:00
|
|
|
|
boolean report, int * academy)
|
- 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
|
|
|
|
{
|
2004-05-24 15:19:41 +02:00
|
|
|
|
teaching_info * teach = NULL;
|
|
|
|
|
attrib * a;
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
/* learning sind die Tage, die sie schon durch andere Lehrer zugute
|
|
|
|
|
* geschrieben bekommen haben. Total darf dies nicht <EFBFBD>ber 30 Tage pro Mann
|
|
|
|
|
* steigen.
|
|
|
|
|
*
|
|
|
|
|
* n ist die Anzahl zus<EFBFBD>tzlich gelernter Tage. n darf max. die Differenz
|
|
|
|
|
* von schon gelernten Tagen zum max(30 Tage pro Mann) betragen. */
|
|
|
|
|
|
|
|
|
|
if (magic_lowskill(student)){
|
|
|
|
|
cmistake(teacher, teacher->thisorder, 292, MSG_EVENT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2004-05-14 12:07:36 +02:00
|
|
|
|
|
2004-05-24 15:19:41 +02:00
|
|
|
|
n = student->number * 30;
|
|
|
|
|
a = a_find(student->attribs, &at_learning);
|
|
|
|
|
if (a!=NULL) {
|
|
|
|
|
teach = (teaching_info*)a->data.v;
|
|
|
|
|
n -= teach->value;
|
|
|
|
|
}
|
- 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
|
|
|
|
|
2004-05-24 15:19:41 +02:00
|
|
|
|
n = min(n, nteaching);
|
|
|
|
|
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
struct building * b = inside_building(teacher);
|
|
|
|
|
const struct building_type * btype = b?b->type:NULL;
|
|
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
|
|
if (teach==NULL) {
|
|
|
|
|
a = a_add(&student->attribs, a_new(&at_learning));
|
|
|
|
|
teach = (teaching_info*)a->data.v;
|
|
|
|
|
} else {
|
2004-05-24 15:22:43 +02:00
|
|
|
|
while (teach->teachers[index] && index!=MAXTEACHERS) ++index;
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
2004-05-24 15:22:43 +02:00
|
|
|
|
if (index<MAXTEACHERS) teach->teachers[index++] = teacher;
|
|
|
|
|
if (index<MAXTEACHERS) teach->teachers[index] = NULL;
|
2004-05-24 15:19:41 +02:00
|
|
|
|
teach->value += n;
|
|
|
|
|
|
|
|
|
|
/* Solange Akademien gr<67><72>enbeschr<68>nkt sind, sollte Lehrer und
|
|
|
|
|
* Student auch in unterschiedlichen Geb<EFBFBD>uden stehen d<EFBFBD>rfen */
|
|
|
|
|
if (btype == bt_find("academy")
|
|
|
|
|
&& student->building && student->building->type == bt_find("academy"))
|
|
|
|
|
{
|
|
|
|
|
int j = study_cost(student, sk);
|
|
|
|
|
j = max(50, j * 2);
|
|
|
|
|
/* kann Einheit das zahlen? */
|
2005-10-30 16:42:15 +01:00
|
|
|
|
if (get_pooled(student, oldresourcetype[R_SILVER], GET_DEFAULT) >= j) {
|
2004-05-24 15:19:41 +02:00
|
|
|
|
/* Jeder Sch<63>ler zus<75>tzlich +10 Tage wenn in Uni. */
|
|
|
|
|
teach->value += (n / 30) * 10; /* learning erh<72>hen */
|
|
|
|
|
/* Lehrer zus<75>tzlich +1 Tag pro Sch<63>ler. */
|
|
|
|
|
if (academy) *academy += n;
|
|
|
|
|
} /* sonst nehmen sie nicht am Unterricht teil */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da
|
|
|
|
|
* hier nicht n verwendet wird, werden die Leute gez<EFBFBD>hlt und nicht die
|
|
|
|
|
* effektiv gelernten Tage. -> FALSCH ? (ENNO)
|
|
|
|
|
*
|
|
|
|
|
* Eine Einheit A von 11 Mann mit Talent 0 profitiert vom ersten Lehrer B
|
|
|
|
|
* also 10x30=300 tage, und der zweite Lehrer C lehrt f<EFBFBD>r nur noch 1x30=30
|
|
|
|
|
* Tage (damit das Maximum von 11x30=330 nicht <EFBFBD>berschritten wird).
|
|
|
|
|
*
|
|
|
|
|
* Damit es aber in der Ausf<EFBFBD>hrung nicht auf die Reihenfolge drauf ankommt,
|
|
|
|
|
* darf der zweite Lehrer C keine weiteren Einheiten D mehr lehren. Also
|
|
|
|
|
* wird student 30 Tage gutgeschrieben, aber teaching sinkt auf 0 (300-11x30 <=
|
|
|
|
|
* 0).
|
|
|
|
|
*
|
|
|
|
|
* Sonst tr<EFBFBD>te dies auf:
|
|
|
|
|
*
|
|
|
|
|
* A: lernt B: lehrt A C: lehrt A D D: lernt
|
|
|
|
|
*
|
|
|
|
|
* Wenn B vor C dran ist, lehrt C nur 30 Tage an A (wie oben) und
|
|
|
|
|
* 270 Tage an D.
|
|
|
|
|
*
|
|
|
|
|
* Ist C aber vor B dran, lehrt C 300 tage an A, und 0 tage an D,
|
|
|
|
|
* und B lehrt auch 0 tage an A.
|
|
|
|
|
*
|
|
|
|
|
* Deswegen darf C D nie lehren d<EFBFBD>rfen.
|
|
|
|
|
*
|
|
|
|
|
* -> Das ist wirr. wer hat das entworfen?
|
|
|
|
|
* Besser w<EFBFBD>re, man macht erst vorab alle zuordnungen, und dann
|
|
|
|
|
* die Talent<EFBFBD>nderung (enno).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
nteaching = max(0, nteaching - student->number * 30);
|
- 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
|
|
|
|
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
|
|
|
|
return n;
|
- 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
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static void
|
2004-06-21 18:45:27 +02:00
|
|
|
|
teach(unit * u, struct order * ord)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-06-21 18:45:27 +02:00
|
|
|
|
region * r = u->region;
|
2005-04-30 19:07:46 +02:00
|
|
|
|
int teaching, i, j, count, academy=0;
|
|
|
|
|
unit *u2;
|
|
|
|
|
skill_t sk = NOSKILL;
|
|
|
|
|
|
|
|
|
|
if ((u->race->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) {
|
|
|
|
|
cmistake(u, ord, 274, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-04-30 19:07:46 +02:00
|
|
|
|
if (r->planep && fval(r->planep, PFL_NOTEACH)) {
|
|
|
|
|
cmistake(u, ord, 273, MSG_EVENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-04-30 19:07:46 +02:00
|
|
|
|
teaching = u->number * 30 * TEACHNUMBER;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2005-04-30 19:07:46 +02:00
|
|
|
|
if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */
|
|
|
|
|
i = min(i, u->number * TEACHNUMBER);
|
|
|
|
|
/* Trank wirkt pro Sch<63>ler, nicht pro Lehrer */
|
|
|
|
|
teaching -= i * 30;
|
|
|
|
|
change_effect(u, oldpotiontype[P_FOOL], -i);
|
|
|
|
|
j = teaching / 30;
|
2006-01-29 01:28:46 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("teachdumb",
|
2005-04-30 19:07:46 +02:00
|
|
|
|
"teacher amount", u, j));
|
|
|
|
|
}
|
|
|
|
|
if (teaching == 0) return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
|
2005-04-30 19:07:46 +02:00
|
|
|
|
u2 = 0;
|
|
|
|
|
count = 0;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
|
- 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 TEACH_ALL
|
2005-04-30 19:07:46 +02:00
|
|
|
|
if (getparam(u->faction->locale)==P_ANY) {
|
|
|
|
|
unit * student = r->units;
|
|
|
|
|
skill_t teachskill[MAXSKILLS];
|
|
|
|
|
int i = 0;
|
|
|
|
|
do {
|
|
|
|
|
sk = getskill(u->faction->locale);
|
|
|
|
|
teachskill[i++]=sk;
|
|
|
|
|
} while (sk!=NOSKILL);
|
|
|
|
|
while (teaching && student) {
|
|
|
|
|
if (student->faction == u->faction) {
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#ifdef NEW_DAEMONHUNGER_RULE
|
2005-04-30 19:07:46 +02:00
|
|
|
|
if (LongHunger(student)) continue;
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#else
|
2005-04-30 19:07:46 +02:00
|
|
|
|
if (fval(student, UFL_HUNGER)) continue;
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#endif
|
2005-04-30 19:07:46 +02:00
|
|
|
|
if (get_keyword(student->thisorder) == K_STUDY) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
/* Input ist nun von student->thisorder !! */
|
|
|
|
|
init_tokens(student->thisorder);
|
|
|
|
|
skip_token();
|
2005-04-30 19:07:46 +02:00
|
|
|
|
sk = getskill(student->faction->locale);
|
|
|
|
|
if (sk!=NOSKILL && teachskill[0]!=NOSKILL) {
|
|
|
|
|
for (i=0;teachskill[i]!=NOSKILL;++i) if (sk==teachskill[i]) break;
|
|
|
|
|
sk = teachskill[i];
|
|
|
|
|
}
|
|
|
|
|
if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE > eff_skill_study(student, sk, r)) {
|
|
|
|
|
teaching -= teach_unit(u, student, teaching, sk, true, &academy);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
student = student->next;
|
|
|
|
|
}
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#ifdef TEACH_FRIENDS
|
2005-04-30 19:07:46 +02:00
|
|
|
|
while (teaching && student) {
|
|
|
|
|
if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) {
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#ifdef NEW_DAEMONHUNGER_RULE
|
2005-04-30 19:07:46 +02:00
|
|
|
|
if (LongHunger(student)) continue;
|
2004-08-03 17:34:26 +02:00
|
|
|
|
#else
|
|
|
|
|
if (fval(student, UFL_HUNGER)) continue;
|
|
|
|
|
#endif
|
2005-04-30 19:07:46 +02:00
|
|
|
|
if (get_keyword(student->thisorder) == K_STUDY) {
|
|
|
|
|
/* Input ist nun von student->thisorder !! */
|
2004-06-21 18:45:27 +02:00
|
|
|
|
init_tokens(student->thisorder);
|
|
|
|
|
skip_token();
|
2005-04-30 19:07:46 +02:00
|
|
|
|
sk = getskill(student->faction->locale);
|
|
|
|
|
if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE >= eff_skill(student, sk, r)) {
|
|
|
|
|
teaching -= teach_unit(u, student, teaching, sk, true, &academy);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
student = student->next;
|
|
|
|
|
}
|
- 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
|
|
|
|
#endif
|
2005-04-30 19:07:46 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
- 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
|
|
|
|
#endif
|
2005-04-30 19:07:46 +02:00
|
|
|
|
{
|
|
|
|
|
static char zOrder[BUFSIZE];
|
|
|
|
|
order * new_order;
|
|
|
|
|
|
2005-05-01 18:24:36 +02:00
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
|
|
|
|
|
2005-04-30 19:07:46 +02:00
|
|
|
|
strcpy(zOrder, locale_string(u->faction->locale, keywords[K_TEACH]));
|
|
|
|
|
|
2005-05-01 18:33:27 +02:00
|
|
|
|
while (!parser_end()) {
|
|
|
|
|
unit * u2 = getunit(r, u->faction);
|
|
|
|
|
++count;
|
2005-04-30 19:07:46 +02:00
|
|
|
|
|
2005-05-01 18:33:27 +02:00
|
|
|
|
/* Falls die Unit nicht gefunden wird, Fehler melden */
|
2005-04-30 19:07:46 +02:00
|
|
|
|
|
|
|
|
|
if (!u2) {
|
2005-05-01 18:33:27 +02:00
|
|
|
|
const char * token;
|
2005-04-30 19:07:46 +02:00
|
|
|
|
/* Finde den string, der den Fehler verursacht hat */
|
|
|
|
|
parser_pushstate();
|
|
|
|
|
init_tokens(ord);
|
|
|
|
|
skip_token();
|
2005-05-01 18:33:27 +02:00
|
|
|
|
|
|
|
|
|
for (j=0; j!=count-1; ++j) {
|
2005-04-30 19:07:46 +02:00
|
|
|
|
/* skip over the first 'count' units */
|
|
|
|
|
getunit(r, u->faction);
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-01 18:33:27 +02:00
|
|
|
|
token = getstrtoken();
|
2005-04-30 19:07:46 +02:00
|
|
|
|
|
|
|
|
|
/* Beginne die Fehlermeldung */
|
|
|
|
|
strcpy(buf, "Die Einheit '");
|
|
|
|
|
|
2005-05-01 18:33:27 +02:00
|
|
|
|
if (findparam(token, u->faction->locale) == P_TEMP) {
|
2005-04-30 19:07:46 +02:00
|
|
|
|
/* F<>r: "Die Einheit 'TEMP ZET' wurde nicht gefunden" oder "Die Einheit
|
|
|
|
|
* 'TEMP' wurde nicht gefunden" */
|
2005-05-01 18:33:27 +02:00
|
|
|
|
scat(token);
|
|
|
|
|
token = getstrtoken();
|
|
|
|
|
if (*token) scat(" ");
|
2005-04-30 19:07:46 +02:00
|
|
|
|
}
|
2005-05-01 18:33:27 +02:00
|
|
|
|
scat(token);
|
2005-04-30 19:07:46 +02:00
|
|
|
|
scat("' wurde nicht gefunden");
|
|
|
|
|
mistake(u, ord, buf, MSG_EVENT);
|
|
|
|
|
|
|
|
|
|
parser_popstate();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2005-05-01 18:33:27 +02:00
|
|
|
|
|
|
|
|
|
/* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in
|
|
|
|
|
* ihre neuen Nummern <EFBFBD>bersetzt. */
|
2005-04-30 19:07:46 +02:00
|
|
|
|
strcat(zOrder, " ");
|
|
|
|
|
strcat(zOrder, unitid(u2));
|
|
|
|
|
|
|
|
|
|
if (get_keyword(u2->thisorder) != K_STUDY) {
|
2006-01-29 01:28:46 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs,
|
2005-04-30 19:07:46 +02:00
|
|
|
|
msg_feedback(u, ord, "teach_nolearn", "student", u2));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2005-05-01 15:08:11 +02:00
|
|
|
|
|
2005-04-30 19:07:46 +02:00
|
|
|
|
/* Input ist nun von u2->thisorder !! */
|
2005-05-01 15:08:11 +02:00
|
|
|
|
parser_pushstate();
|
2005-04-30 19:07:46 +02:00
|
|
|
|
init_tokens(u2->thisorder);
|
|
|
|
|
skip_token();
|
|
|
|
|
sk = getskill(u2->faction->locale);
|
2005-05-01 15:33:34 +02:00
|
|
|
|
parser_popstate();
|
2005-05-01 15:08:11 +02:00
|
|
|
|
|
2005-04-30 19:07:46 +02:00
|
|
|
|
if (sk == NOSKILL) {
|
2006-01-29 01:28:46 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs,
|
2005-04-30 19:07:46 +02:00
|
|
|
|
msg_feedback(u, ord, "teach_nolearn", "student", u2));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* u is teacher, u2 is student */
|
|
|
|
|
if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r)-TEACHDIFFERENCE) {
|
2006-01-29 01:28:46 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs,
|
2005-04-30 19:07:46 +02:00
|
|
|
|
msg_feedback(u, ord, "teach_asgood", "student", u2));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (sk == SK_MAGIC) {
|
|
|
|
|
/* ist der Magier schon spezialisiert, so versteht er nur noch
|
|
|
|
|
* Lehrer seines Gebietes */
|
|
|
|
|
if (find_magetype(u2) != 0
|
|
|
|
|
&& find_magetype(u) != find_magetype(u2))
|
|
|
|
|
{
|
|
|
|
|
sprintf(buf, "%s versteht unsere Art von Magie nicht", unitname(u2));
|
|
|
|
|
mistake(u, ord, buf, MSG_EVENT);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
teaching -= teach_unit(u, u2, teaching, sk, false, &academy);
|
- 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
|
|
|
|
|
2005-04-30 19:07:46 +02:00
|
|
|
|
}
|
|
|
|
|
new_order = parse_order(zOrder, u->faction->locale);
|
|
|
|
|
#ifdef LASTORDER
|
|
|
|
|
set_order(&u->lastorder, new_order);
|
|
|
|
|
#else
|
2005-05-22 14:29:56 +02:00
|
|
|
|
replace_order(&u->orders, ord, new_order);
|
2005-04-30 19:07:46 +02:00
|
|
|
|
free_order(new_order); /* parse_order & set_order have each increased the refcount */
|
2005-05-10 00:30:43 +02:00
|
|
|
|
#endif
|
2005-04-30 19:07:46 +02:00
|
|
|
|
}
|
|
|
|
|
if (academy && sk!=NOSKILL) {
|
|
|
|
|
academy = academy/30; /* anzahl gelehrter wochen, max. 10 */
|
|
|
|
|
learn_skill(u, sk, academy/30.0/TEACHNUMBER);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
/* ------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
learn(void)
|
|
|
|
|
{
|
2004-05-24 15:19:41 +02:00
|
|
|
|
region *r;
|
|
|
|
|
unit *u;
|
|
|
|
|
int p;
|
|
|
|
|
magic_t mtyp;
|
|
|
|
|
int l;
|
|
|
|
|
int warrior_skill;
|
|
|
|
|
int studycost;
|
|
|
|
|
|
|
|
|
|
/* lernen nach lehren */
|
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
int days;
|
2005-10-25 14:38:01 +02:00
|
|
|
|
if (fval(r->terrain, SEA_REGION)) {
|
2004-05-24 15:19:41 +02:00
|
|
|
|
/* sonderbehandlung aller die auf Ozeanen lernen k<>nnen */
|
2005-05-27 23:03:48 +02:00
|
|
|
|
if (u->race!=new_race[RC_AQUARIAN] && !(u->race->flags & RCF_SWIM)) {
|
2004-05-24 15:19:41 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-05-27 23:03:48 +02:00
|
|
|
|
if (fval(u, UFL_LONGACTION)) continue;
|
2004-12-03 20:08:00 +01:00
|
|
|
|
if (get_keyword(u->thisorder) == K_STUDY) {
|
2004-05-24 15:19:41 +02:00
|
|
|
|
double multi = 1.0;
|
|
|
|
|
attrib * a = NULL;
|
|
|
|
|
teaching_info * teach = NULL;
|
|
|
|
|
int money = 0;
|
|
|
|
|
skill_t sk;
|
|
|
|
|
int maxalchemy = 0;
|
2004-06-21 18:45:27 +02:00
|
|
|
|
|
2004-05-24 15:19:41 +02:00
|
|
|
|
if (u->race == new_race[RC_INSECT] && r_insectstalled(r)
|
|
|
|
|
&& !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) {
|
2004-10-16 14:15:22 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (attacked(u)) {
|
2004-12-03 20:08:00 +01:00
|
|
|
|
cmistake(u, u->thisorder, 52, MSG_PRODUCE);
|
2004-10-16 14:15:22 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if ((u->race->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) {
|
|
|
|
|
sprintf(buf, "%s k<>nnen nichts lernen", LOC(default_locale, rc_name(u->race, 1)));
|
|
|
|
|
mistake(u, u->thisorder, buf, MSG_EVENT);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
init_tokens(u->thisorder);
|
|
|
|
|
skip_token();
|
|
|
|
|
sk = getskill(u->faction->locale);
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
if (sk < 0) {
|
2004-12-03 20:08:00 +01:00
|
|
|
|
cmistake(u, u->thisorder, 77, MSG_EVENT);
|
2004-10-16 14:15:22 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) {
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 77, MSG_EVENT);
|
2004-10-16 14:15:22 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Hack: Talente mit Malus -99 k<>nnen nicht gelernt werden */
|
|
|
|
|
if (u->race->bonus[sk] == -99) {
|
|
|
|
|
cmistake(u, u->thisorder, 77, MSG_EVENT);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* snotlings k<>nnen Talente nur bis T8 lernen */
|
|
|
|
|
if (u->race == new_race[RC_SNOTLING]){
|
|
|
|
|
if (get_level(u, sk) >= 8){
|
|
|
|
|
cmistake(u, u->thisorder, 308, MSG_EVENT);
|
2004-05-24 15:19:41 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
p = studycost = study_cost(u, sk);
|
|
|
|
|
a = a_find(u->attribs, &at_learning);
|
|
|
|
|
if (a!=NULL) {
|
|
|
|
|
teach = (teaching_info*)a->data.v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* keine kostenpflichtigen Talente f<>r Migranten. Vertraute sind
|
|
|
|
|
* keine Migranten, wird in is_migrant abgefangen. Vorsicht,
|
|
|
|
|
* studycost darf hier noch nicht durch Akademie erh<EFBFBD>ht sein */
|
|
|
|
|
if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) {
|
|
|
|
|
sprintf(buf, "Migranten k<>nnen keine kostenpflichtigen Talente lernen");
|
|
|
|
|
mistake(u, u->thisorder, buf, MSG_EVENT);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Akademie: */
|
|
|
|
|
{
|
|
|
|
|
struct building * b = inside_building(u);
|
|
|
|
|
const struct building_type * btype = b?b->type:NULL;
|
|
|
|
|
|
|
|
|
|
if (btype == bt_find("academy")) {
|
|
|
|
|
studycost = max(50, studycost * 2);
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
if (sk == SK_MAGIC) {
|
|
|
|
|
if (u->number > 1){
|
|
|
|
|
cmistake(u, u->thisorder, 106, MSG_MAGIC);
|
2004-05-24 15:19:41 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
if (is_familiar(u)){
|
|
|
|
|
/* Vertraute z<>hlen nicht zu den Magiern einer Partei,
|
|
|
|
|
* k<EFBFBD>nnen aber nur Graue Magie lernen */
|
|
|
|
|
mtyp = M_GRAU;
|
2006-01-29 09:50:53 +01:00
|
|
|
|
if (!is_mage(u)) create_mage(u, mtyp);
|
2005-11-25 18:07:41 +01:00
|
|
|
|
} else if (!has_skill(u, SK_MAGIC)) {
|
2004-10-16 14:15:22 +02:00
|
|
|
|
/* Die Einheit ist noch kein Magier */
|
|
|
|
|
if (count_skill(u->faction, SK_MAGIC) + u->number >
|
|
|
|
|
max_skill(u->faction, SK_MAGIC))
|
|
|
|
|
{
|
|
|
|
|
sprintf(buf, "Es kann maximal %d Magier pro Partei geben",
|
|
|
|
|
max_skill(u->faction, SK_MAGIC));
|
|
|
|
|
mistake(u, u->thisorder, buf, MSG_EVENT);
|
2004-05-24 15:19:41 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
mtyp = getmagicskill();
|
|
|
|
|
if (mtyp == M_NONE || mtyp == M_GRAU) {
|
|
|
|
|
/* wurde kein Magiegebiet angegeben, wird davon
|
|
|
|
|
* ausgegangen, da<EFBFBD> das normal gelernt werden soll */
|
|
|
|
|
if(u->faction->magiegebiet != 0) {
|
|
|
|
|
mtyp = u->faction->magiegebiet;
|
|
|
|
|
} else {
|
|
|
|
|
/* Es wurde kein Magiegebiet angegeben und die Partei
|
|
|
|
|
* hat noch keins gew<EFBFBD>hlt. */
|
|
|
|
|
cmistake(u, u->thisorder, 178, MSG_MAGIC);
|
2004-05-24 15:19:41 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (mtyp != u->faction->magiegebiet){
|
|
|
|
|
/* Es wurde versucht, ein anderes Magiegebiet zu lernen
|
|
|
|
|
* als das der Partei */
|
|
|
|
|
if (u->faction->magiegebiet != 0){
|
|
|
|
|
cmistake(u, u->thisorder, 179, MSG_MAGIC);
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
/* Lernt zum ersten mal Magie und legt damit das
|
|
|
|
|
* Magiegebiet der Partei fest */
|
|
|
|
|
u->faction->magiegebiet = mtyp;
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-01-29 09:50:53 +01:00
|
|
|
|
if (!is_mage(u)) create_mage(u, mtyp);
|
2004-10-16 14:15:22 +02:00
|
|
|
|
} else {
|
|
|
|
|
/* ist schon ein Magier und kein Vertrauter */
|
|
|
|
|
if(u->faction->magiegebiet == 0){
|
|
|
|
|
/* die Partei hat noch kein Magiegebiet gew<65>hlt. */
|
|
|
|
|
mtyp = getmagicskill();
|
|
|
|
|
if (mtyp == M_NONE){
|
|
|
|
|
cmistake(u, u->thisorder, 178, MSG_MAGIC);
|
2004-05-24 15:19:41 +02:00
|
|
|
|
continue;
|
2004-10-16 14:15:22 +02:00
|
|
|
|
} else {
|
|
|
|
|
/* Legt damit das Magiegebiet der Partei fest */
|
|
|
|
|
u->faction->magiegebiet = mtyp;
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (sk == SK_ALCHEMY) {
|
|
|
|
|
maxalchemy = eff_skill(u, SK_ALCHEMY, r);
|
|
|
|
|
if (has_skill(u, SK_ALCHEMY)==0
|
|
|
|
|
&& count_skill(u->faction, SK_ALCHEMY) + u->number >
|
|
|
|
|
max_skill(u->faction, SK_ALCHEMY)) {
|
|
|
|
|
sprintf(buf, "Es kann maximal %d Alchemisten pro Partei geben",
|
|
|
|
|
max_skill(u->faction, SK_ALCHEMY));
|
|
|
|
|
mistake(u, u->thisorder, buf, MSG_EVENT);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (studycost) {
|
2005-10-30 16:42:15 +01:00
|
|
|
|
money = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT);
|
2004-10-16 14:15:22 +02:00
|
|
|
|
money = min(money, studycost * u->number);
|
|
|
|
|
}
|
|
|
|
|
if (money < studycost * u->number) {
|
|
|
|
|
studycost = p; /* Ohne Univertreurung */
|
|
|
|
|
money = min(money, studycost);
|
|
|
|
|
if (p>0 && money < studycost * u->number) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef PARTIAL_STUDY
|
2004-10-16 14:15:22 +02:00
|
|
|
|
cmistake(u, u->thisorder, 65, MSG_EVENT);
|
|
|
|
|
multi = money / (double)(studycost * u->number);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#else
|
2004-10-16 14:15:22 +02:00
|
|
|
|
cmistake(u, u->thisorder, 65, MSG_EVENT);
|
|
|
|
|
continue; /* nein, Silber reicht auch so nicht */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
if (teach==NULL) {
|
|
|
|
|
a = a_add(&u->attribs, a_new(&at_learning));
|
|
|
|
|
teach = (teaching_info*)a->data.v;
|
|
|
|
|
teach->teachers[0] = 0;
|
|
|
|
|
}
|
|
|
|
|
if (money>0) {
|
2005-10-30 16:42:15 +01:00
|
|
|
|
use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, money);
|
2006-01-29 01:28:46 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("studycost",
|
2004-10-16 14:15:22 +02:00
|
|
|
|
"unit region cost skill", u, u->region, money, sk));
|
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
if (get_effect(u, oldpotiontype[P_WISE])) {
|
|
|
|
|
l = min(u->number, get_effect(u, oldpotiontype[P_WISE]));
|
|
|
|
|
teach->value += l * 10;
|
|
|
|
|
change_effect(u, oldpotiontype[P_WISE], -l);
|
|
|
|
|
}
|
|
|
|
|
if (get_effect(u, oldpotiontype[P_FOOL])) {
|
|
|
|
|
l = min(u->number, get_effect(u, oldpotiontype[P_FOOL]));
|
|
|
|
|
teach->value -= l * 30;
|
|
|
|
|
change_effect(u, oldpotiontype[P_FOOL], -l);
|
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
warrior_skill = fspecial(u->faction, FS_WARRIOR);
|
|
|
|
|
if(warrior_skill > 0) {
|
|
|
|
|
if(sk == SK_CROSSBOW || sk == SK_LONGBOW
|
2005-10-02 19:35:25 +02:00
|
|
|
|
|| sk == SK_CATAPULT || sk == SK_MELEE || sk == SK_SPEAR
|
2004-10-16 14:15:22 +02:00
|
|
|
|
|| sk == SK_AUSDAUER || sk == SK_WEAPONLESS)
|
|
|
|
|
{
|
|
|
|
|
teach->value += u->number * (5+warrior_skill*5);
|
|
|
|
|
} else {
|
|
|
|
|
teach->value -= u->number * (5+warrior_skill*5);
|
|
|
|
|
teach->value = max(0, teach->value);
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
if (p != studycost) {
|
|
|
|
|
/* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */
|
|
|
|
|
/* p ist Kosten ohne Uni, studycost mit; wenn
|
|
|
|
|
* p!=studycost, ist die Einheit zwangsweise
|
|
|
|
|
* in einer Uni */
|
|
|
|
|
teach->value += u->number * 10;
|
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
if (is_cursed(r->attribs,C_BADLEARN,0)) {
|
|
|
|
|
teach->value -= u->number * 10;
|
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
days = (int)((u->number * 30 + teach->value) * multi);
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
/* the artacademy currently improves the learning of entertainment
|
|
|
|
|
of all units in the region, to be able to make it cumulative with
|
|
|
|
|
with an academy */
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2005-07-10 18:32:47 +02:00
|
|
|
|
if (buildingtype_exists(r, bt_find("artacademy"))) {
|
2004-10-16 14:15:22 +02:00
|
|
|
|
days *= 2;
|
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
if (fval(u, UFL_HUNGER)) days /= 2;
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
while (days) {
|
|
|
|
|
if (days>=u->number*30) {
|
|
|
|
|
learn_skill(u, sk, 1.0);
|
|
|
|
|
days -= u->number*30;
|
|
|
|
|
} else {
|
|
|
|
|
double chance = (double)days/u->number/30;
|
|
|
|
|
learn_skill(u, sk, chance);
|
|
|
|
|
days = 0;
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (a!=NULL) {
|
|
|
|
|
if (teach!=NULL) {
|
|
|
|
|
int index = 0;
|
|
|
|
|
while (teach->teachers[index] && index!=MAXTEACHERS) {
|
|
|
|
|
unit * teacher = teach->teachers[index++];
|
|
|
|
|
if (teacher->faction != u->faction) {
|
2006-01-29 01:28:46 +01:00
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("teach_student",
|
2004-10-16 14:15:22 +02:00
|
|
|
|
"teacher student skill", teacher, u, sk));
|
2006-01-29 01:28:46 +01:00
|
|
|
|
ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher",
|
2004-10-16 14:15:22 +02:00
|
|
|
|
"teacher student skill level", teacher, u, sk,
|
|
|
|
|
effskill(u, sk)));
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
a_remove(&u->attribs, a);
|
|
|
|
|
a = NULL;
|
|
|
|
|
}
|
2005-06-13 21:54:58 +02:00
|
|
|
|
fset(u, UFL_LONGACTION);
|
2004-05-24 15:19:41 +02:00
|
|
|
|
|
2004-10-16 14:15:22 +02:00
|
|
|
|
/* Anzeigen neuer Tr<54>nke */
|
|
|
|
|
/* Spruchlistenaktualiesierung ist in Regeneration */
|
|
|
|
|
|
|
|
|
|
if (sk == SK_ALCHEMY) {
|
|
|
|
|
const potion_type * ptype;
|
|
|
|
|
faction * f = u->faction;
|
|
|
|
|
int skill = eff_skill(u, SK_ALCHEMY, r);
|
|
|
|
|
if (skill>maxalchemy) {
|
|
|
|
|
for (ptype=potiontypes; ptype; ptype=ptype->next) {
|
|
|
|
|
if (skill == ptype->level * 2) {
|
|
|
|
|
attrib * a = a_find(f->attribs, &at_showitem);
|
|
|
|
|
while (a && a->data.v != ptype) a=a->nexttype;
|
|
|
|
|
if (!a) {
|
|
|
|
|
a = a_add(&f->attribs, a_new(&at_showitem));
|
|
|
|
|
a->data.v = (void*) ptype->itype;
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-10-16 14:15:22 +02:00
|
|
|
|
}
|
2004-05-24 15:19:41 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
teaching(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
/* das sind alles befehle, die 30 tage brauchen, und die in thisorder
|
|
|
|
|
* stehen! von allen 30-tage befehlen wird einfach der letzte verwendet
|
|
|
|
|
* (dosetdefaults).
|
|
|
|
|
*
|
|
|
|
|
* lehren vor lernen. */
|
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
2005-03-06 17:37:10 +01:00
|
|
|
|
unit *u;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
|
2003-07-29 11:48:03 +02:00
|
|
|
|
if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
2005-10-25 14:38:01 +02:00
|
|
|
|
if (fval(r->terrain, SEA_REGION)
|
2001-12-10 01:13:39 +01:00
|
|
|
|
&& u->race != new_race[RC_AQUARIAN]
|
|
|
|
|
&& !(u->race->flags & RCF_SWIM))
|
2001-05-06 23:49:16 +02:00
|
|
|
|
continue;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->race == new_race[RC_INSECT] && r_insectstalled(r)
|
|
|
|
|
&& !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
continue;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-06-21 18:45:27 +02:00
|
|
|
|
switch (get_keyword(u->thisorder)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case K_TEACH:
|
|
|
|
|
if (attacked(u)){
|
2004-06-21 18:45:27 +02:00
|
|
|
|
cmistake(u, u->thisorder, 52, MSG_PRODUCE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
continue;
|
2005-03-06 17:37:10 +01:00
|
|
|
|
} else {
|
|
|
|
|
static const curse_type * gbdream_ct = NULL;
|
|
|
|
|
if (gbdream_ct==0) gbdream_ct = ct_find("gbdream");
|
|
|
|
|
if (gbdream_ct) {
|
|
|
|
|
if (get_curse(u->region->attribs, gbdream_ct)) {
|
|
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
|
msg_feedback(u, u->thisorder, "gbdream_noteach", ""));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-06-21 18:45:27 +02:00
|
|
|
|
teach(u, u->thisorder);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|