diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5b267c0d5..0ff92bf2d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,6 +86,7 @@ ENDIF() set (ERESSEA_SRC vortex.c + automate.c move.c piracy.c spells.c diff --git a/src/automate.c b/src/automate.c new file mode 100644 index 000000000..0855ff0e3 --- /dev/null +++ b/src/automate.c @@ -0,0 +1,71 @@ +#include + +#include "kernel/faction.h" +#include "kernel/order.h" +#include "kernel/region.h" +#include "kernel/unit.h" + +#include "util/log.h" + +#include "automate.h" +#include "keyword.h" +#include "study.h" + +#include + +typedef struct student { + unit *u; + skill_t sk; + int level; +} student; + +#define MAXSTUDENTS 128 + +int cmp_students(const void *lhs, const void *rhs) { + const student *a = (const student *)lhs; + const student *b = (const student *)rhs; + if (a->sk == b->sk) { + /* sort by level, descending: */ + return b->level - a->level; + } + /* order by skill */ + return (int)a->sk - (int)b->sk; +} + +void do_autostudy(region *r) { + unit *u; + int nstudents = 0; + student students[MAXSTUDENTS]; + + for (u = r->units; u; u = u->next) { + keyword_t kwd = getkeyword(u->thisorder); + if (kwd == K_AUTOSTUDY) { + student * st = students + nstudents; + if (++nstudents == MAXSTUDENTS) { + log_fatal("you must increase MAXSTUDENTS"); + } + st->u = u; + init_order(u->thisorder, u->faction->locale); + st->sk = getskill(u->faction->locale); + st->level = effskill_study(u, st->sk); + } + } + if (nstudents > 0) { + int i, taught = 0; + skill_t sk = NOSKILL; + student *teacher = NULL, *student = NULL; + + qsort(students, nstudents, sizeof(student), cmp_students); + for (i = 0; i != nstudents; ++i) { + if (students[i].u) { + if (sk == NOSKILL) { + sk = students[i].sk; + } + else if (sk != students[i].sk) { + continue; + } + students[i].u = NULL; + } + } + } +} diff --git a/src/automate.h b/src/automate.h new file mode 100644 index 000000000..ded8f938b --- /dev/null +++ b/src/automate.h @@ -0,0 +1,28 @@ +/* +Copyright (c) 1998-2018, Enno Rehling +Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#pragma once + +#ifndef H_GC_AUTOMATE +#define H_GC_AUTOMATE + +struct region; + +void do_autostudy(struct region *r); + +#endif diff --git a/src/kernel/config.c b/src/kernel/config.c index ec45ddd0d..750d406f6 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -135,7 +135,8 @@ const char *parameters[MAXPARAMS] = { "GRUPPE", "PARTEITARNUNG", "BAEUME", - "ALLIANZ" + "ALLIANZ", + "AUTO" }; int findoption(const char *s, const struct locale *lang) diff --git a/src/kernel/order.c b/src/kernel/order.c index e660edf81..ac2573758 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -214,12 +214,12 @@ static int create_data(keyword_t kwd, const char *s, order_data *data; int id; - assert(kwd!=NOKEYWORD); + assert(kwd != NOKEYWORD); if (!s || *s == 0) { return 0; } - if (kwd==K_STUDY) { + if (kwd == K_STUDY || kwd == K_AUTOSTUDY) { const char * sptr = s; skill_t sk = get_skill(parse_token_depr(&sptr), lang); if (sk != SK_MAGIC && sk != NOSKILL) { @@ -332,6 +332,14 @@ order *parse_order(const char *s, const struct locale * lang) sptr = sp; } } + else if (kwd == K_STUDY) { + const char *sp = sptr; + p = parse_token_depr(&sp); + if (p && isparam(p, lang, P_AUTO)) { + kwd = K_AUTOSTUDY; + sptr = sp; + } + } if (kwd != NOKEYWORD) { order *ord = (order *)malloc(sizeof(order)); create_order_i(ord, kwd, sptr, persistent, noerror, lang); @@ -366,6 +374,7 @@ bool is_repeated(keyword_t kwd) case K_STEAL: case K_SABOTAGE: case K_STUDY: + case K_AUTOSTUDY: case K_TEACH: case K_GROW: case K_PLANT: @@ -406,6 +415,7 @@ bool is_exclusive(const order * ord) case K_STEAL: case K_SABOTAGE: case K_STUDY: + case K_AUTOSTUDY: case K_TEACH: case K_GROW: case K_PLANT: @@ -447,6 +457,7 @@ bool is_long(keyword_t kwd) case K_STEAL: case K_SABOTAGE: case K_STUDY: + case K_AUTOSTUDY: case K_TEACH: case K_GROW: case K_PLANT: @@ -541,7 +552,7 @@ keyword_t init_order(const struct order *ord, const struct locale *lang) assert(sk < MAXSKILLS); assert(lang); - assert(kwd == K_STUDY); + assert(kwd == K_STUDY || kwd == K_AUTOSTUDY); str = skillname(sk, lang); if (strchr(str, ' ') == NULL) { init_tokens_str(str); @@ -575,7 +586,7 @@ keyword_t init_order_depr(const struct order *ord) { if (ord) { keyword_t kwd = ORD_KEYWORD(ord); - assert(kwd != K_STUDY); + assert(kwd != K_STUDY && kwd != K_AUTOSTUDY); } return init_order(ord, NULL); } diff --git a/src/kernel/types.h b/src/kernel/types.h index 61f1268cc..48a4326fa 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -130,6 +130,7 @@ typedef enum { P_FACTIONSTEALTH, P_TREES, P_ALLIANCE, + P_AUTO, MAXPARAMS, NOPARAM } param_t; diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 07c6c0856..770723bea 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1310,13 +1310,12 @@ int eff_skill(const unit * u, const skill *sv, const region *r) return 0; } -int effskill_study(const unit * u, skill_t sk, const region * r) +int effskill_study(const unit * u, skill_t sk) { skill *sv = unit_skill(u, sk); if (sv && sv->level > 0) { int mlevel = sv->level; - if (!r) r = u->region; - mlevel += get_modifier(u, sv->id, sv->level, r, true); + mlevel += get_modifier(u, sv->id, sv->level, u->region, true); if (mlevel > 0) return mlevel; } diff --git a/src/kernel/unit.h b/src/kernel/unit.h index ac61affde..a6135715c 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -163,7 +163,7 @@ extern "C" { void clone_men(const struct unit *src, struct unit *dst, int n); /* like transfer, but do not subtract from src */ int eff_skill(const struct unit *u, const struct skill *sv, const struct region *r); - int effskill_study(const struct unit *u, skill_t sk, const struct region *r); + int effskill_study(const struct unit *u, skill_t sk); int get_modifier(const struct unit *u, skill_t sk, int level, const struct region *r, bool noitem); diff --git a/src/keyword.c b/src/keyword.c index 7519b6449..48726bcbc 100644 --- a/src/keyword.c +++ b/src/keyword.c @@ -149,5 +149,6 @@ const char *keywords[MAXKEYWORDS] = { "promote", "pay", "loot", + "autostudy", }; diff --git a/src/keyword.h b/src/keyword.h index a9273c3f5..6e4832708 100644 --- a/src/keyword.h +++ b/src/keyword.h @@ -72,6 +72,7 @@ extern "C" K_PROMOTION, K_PAY, K_LOOT, + K_AUTOSTUDY, MAXKEYWORDS, NOKEYWORD } keyword_t; diff --git a/src/laws.c b/src/laws.c index aa6e237e2..3902e9a8e 100644 --- a/src/laws.c +++ b/src/laws.c @@ -26,6 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "alchemy.h" +#include "automate.h" #include "battle.h" #include "economy.h" #include "keyword.h" @@ -4011,6 +4012,7 @@ void init_processor(void) } p += 10; + add_proc_region(p, do_autostudy, "study automation"); add_proc_order(p, K_TEACH, teach_cmd, PROC_THISORDER | PROC_LONGORDER, "Lehren"); p += 10; diff --git a/src/study.c b/src/study.c index 46da90b74..6df5b5eaf 100644 --- a/src/study.c +++ b/src/study.c @@ -69,7 +69,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define TEACH_ALL 1 #define TEACH_FRIENDS -static skill_t getskill(const struct locale *lang) +skill_t getskill(const struct locale *lang) { char token[128]; const char * s = gettoken(token, sizeof(token)); @@ -331,7 +331,7 @@ int teach_cmd(unit * teacher, struct order *ord) sk = teachskill[t]; } if (sk != NOSKILL - && effskill_study(teacher, sk, 0) - TEACHDIFFERENCE > effskill_study(student, sk, 0)) { + && effskill_study(teacher, sk) - TEACHDIFFERENCE > effskill_study(student, sk)) { teaching -= teach_unit(teacher, student, teaching, sk, true, &academy_students); } } @@ -343,7 +343,7 @@ int teach_cmd(unit * teacher, struct order *ord) init_order(student->thisorder, student->faction->locale); sk = getskill(student->faction->locale); if (sk != NOSKILL - && effskill_study(teacher, sk, 0) - TEACHDIFFERENCE >= effskill(student, sk, 0)) { + && effskill_study(teacher, sk) - TEACHDIFFERENCE >= effskill(student, sk)) { teaching -= teach_unit(teacher, student, teaching, sk, true, &academy_students); } } @@ -432,7 +432,7 @@ int teach_cmd(unit * teacher, struct order *ord) continue; } - if (effskill_study(student, sk, 0) > effskill_study(teacher, sk, 0) + if (effskill_study(student, sk, NULL) > effskill_study(teacher, sk) - TEACHDIFFERENCE) { if (feedback) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_asgood", diff --git a/src/study.h b/src/study.h index b4b76bb8c..e99fb4808 100644 --- a/src/study.h +++ b/src/study.h @@ -33,6 +33,7 @@ extern "C" { int study_cmd(struct unit *u, struct order *ord); magic_t getmagicskill(const struct locale *lang); + skill_t getskill(const struct locale *lang); bool is_migrant(struct unit *u); int study_cost(struct unit *u, skill_t talent);