diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fb03ebbe7..a1a63c15a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -111,6 +111,7 @@ set (ERESSEA_SRC morale.c monster.c randenc.c + volcano.c chaos.c report.c spy.c diff --git a/src/randenc.c b/src/randenc.c index 6a642557b..699da5367 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -20,10 +20,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "randenc.h" +#include "volcano.h" #include "economy.h" #include "monster.h" #include "move.h" -#include "alchemy.h" #include "chaos.h" #include "study.h" @@ -412,118 +412,6 @@ void encounters(void) } } -static int nb_armor(const unit * u, int index) -{ - const item *itm; - int av = 0; - int s = 0, a = 0; - - if (!(u_race(u)->battle_flags & BF_EQUIPMENT)) - return 0; - - /* Normale Rüstung */ - - for (itm = u->items; itm; itm = itm->next) { - const armor_type *atype = itm->type->rtype->atype; - if (atype != NULL) { - int *schutz = &a; - if (atype->flags & ATF_SHIELD) - schutz = &s; - if (*schutz <= index) { - *schutz += itm->number; - if (*schutz > index) { - av += atype->prot; - } - } - } - } - return av; -} - -static int -damage_unit(unit * u, const char *dam, bool physical, bool magic) -{ - int *hp, hpstack[20]; - int h; - int i, dead = 0, hp_rem = 0, heiltrank; - double magres = magic_resistance(u); - - assert(u->number); - if (fval(u_race(u), RCF_ILLUSIONARY) || u_race(u) == get_race(RC_SPELL)) { - return 0; - } - - assert(u->number <= u->hp); - h = u->hp / u->number; - /* HP verteilen */ - if (u->number < 20) { - hp = hpstack; - } - else { - hp = malloc(u->number * sizeof(int)); - } - for (i = 0; i < u->number; i++) - hp[i] = h; - h = u->hp - (u->number * h); - for (i = 0; i < h; i++) - hp[i]++; - - /* Schaden */ - for (i = 0; i < u->number; i++) { - int damage = dice_rand(dam); - if (magic) - damage = (int)(damage * (1.0 - magres)); - if (physical) - damage -= nb_armor(u, i); - hp[i] -= damage; - } - - /* Auswirkungen */ - for (i = 0; i < u->number; i++) { - if (hp[i] <= 0) { - heiltrank = 0; - - /* Sieben Leben */ - if (old_race(u_race(u)) == RC_CAT && (chance(1.0 / 7))) { - hp[i] = u->hp / u->number; - hp_rem += hp[i]; - continue; - } - - /* Heiltrank */ - if (oldpotiontype[P_HEAL]) { - if (get_effect(u, oldpotiontype[P_HEAL]) > 0) { - change_effect(u, oldpotiontype[P_HEAL], -1); - heiltrank = 1; - } - else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) { - i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1); - change_effect(u, oldpotiontype[P_HEAL], 3); - heiltrank = 1; - } - if (heiltrank && (chance(0.50))) { - hp[i] = u->hp / u->number; - hp_rem += hp[i]; - continue; - } - } - dead++; - } - else { - hp_rem += hp[i]; - } - } - - scale_number(u, u->number - dead); - u->hp = hp_rem; - - if (hp != hpstack) { - free(hp); - } - - return dead; -} - void drown(region * r) { if (fval(r->terrain, SEA_REGION)) { @@ -542,106 +430,6 @@ void drown(region * r) } } -region *rrandneighbour(region * r) -{ - direction_t i; - region *rc = NULL; - int rr, c = 0; - - /* Nachsehen, wieviele Regionen in Frage kommen */ - - for (i = 0; i != MAXDIRECTIONS; i++) { - c++; - } - /* Zufällig eine auswählen */ - - rr = rng_int() % c; - - /* Durchzählen */ - - c = -1; - for (i = 0; i != MAXDIRECTIONS; i++) { - rc = rconnect(r, i); - c++; - if (c == rr) - break; - } - assert(i != MAXDIRECTIONS); - return rc; -} - -static void -volcano_destruction(region * volcano, region * r, const char *damage) -{ - attrib *a; - unit **up; - int percent = 25, time = 6 + rng_int() % 12; - - rsettrees(r, 2, 0); - rsettrees(r, 1, 0); - rsettrees(r, 0, 0); - - a = a_find(r->attribs, &at_reduceproduction); - if (!a) { - a = a_add(&r->attribs, make_reduceproduction(percent, time)); - } - else { - /* Produktion vierteln ... */ - a->data.sa[0] = (short)percent; - /* Für 6-17 Runden */ - a->data.sa[1] = (short)(a->data.sa[1] + time); - } - - /* Personen bekommen 4W10 Punkte Schaden. */ - - for (up = &r->units; *up;) { - unit *u = *up; - if (u->number) { - int dead = damage_unit(u, damage, true, false); - /* TODO create undead */ - if (dead) { - ADDMSG(&u->faction->msgs, msg_message("volcano_dead", - "unit region dead", u, volcano, dead)); - } - if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn", - "region", r)); - } - } - if (u == *up) { - up = &u->next; - } - } - - if (r != volcano) { - ADDMSG(&r->msgs, msg_message("volcanooutbreak", - "regionv regionn", volcano, r)); - } - remove_empty_units_in_region(r); -} - -void volcano_outbreak(region * r) -{ - region *rn; - unit *u; - faction *f; - - for (f = NULL, u = r->units; u; u = u->next) { - if (f != u->faction) { - f = u->faction; - freset(f, FFL_SELECT); - } - } - - /* Zufällige Nachbarregion verwüsten */ - rn = rrandneighbour(r); - volcano_destruction(r, r, "4d10"); - if (rn) { - volcano_destruction(r, rn, "3d10"); - } -} - static void melt_iceberg(region * r) { attrib *a; diff --git a/src/volcano.c b/src/volcano.c new file mode 100644 index 000000000..b9fc1fc16 --- /dev/null +++ b/src/volcano.c @@ -0,0 +1,259 @@ +/* +Copyright (c) 1998-2015, 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. +**/ + +#include +#include +#include "volcano.h" + +#include "alchemy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include + +static int nb_armor(const unit * u, int index) +{ + const item *itm; + int av = 0; + int s = 0, a = 0; + + if (!(u_race(u)->battle_flags & BF_EQUIPMENT)) + return 0; + + /* Normale Rüstung */ + + for (itm = u->items; itm; itm = itm->next) { + const armor_type *atype = itm->type->rtype->atype; + if (atype != NULL) { + int *schutz = &a; + if (atype->flags & ATF_SHIELD) + schutz = &s; + if (*schutz <= index) { + *schutz += itm->number; + if (*schutz > index) { + av += atype->prot; + } + } + } + } + return av; +} + +static int +damage_unit(unit * u, const char *dam, bool physical, bool magic) +{ + int *hp, hpstack[20]; + int h; + int i, dead = 0, hp_rem = 0, heiltrank; + double magres = magic_resistance(u); + + assert(u->number); + if (fval(u_race(u), RCF_ILLUSIONARY) || u_race(u) == get_race(RC_SPELL)) { + return 0; + } + + assert(u->number <= u->hp); + h = u->hp / u->number; + /* HP verteilen */ + if (u->number < 20) { + hp = hpstack; + } + else { + hp = malloc(u->number * sizeof(int)); + } + for (i = 0; i < u->number; i++) + hp[i] = h; + h = u->hp - (u->number * h); + for (i = 0; i < h; i++) + hp[i]++; + + /* Schaden */ + for (i = 0; i < u->number; i++) { + int damage = dice_rand(dam); + if (magic) + damage = (int)(damage * (1.0 - magres)); + if (physical) + damage -= nb_armor(u, i); + hp[i] -= damage; + } + + /* Auswirkungen */ + for (i = 0; i < u->number; i++) { + if (hp[i] <= 0) { + heiltrank = 0; + + /* Sieben Leben */ + if (old_race(u_race(u)) == RC_CAT && (chance(1.0 / 7))) { + hp[i] = u->hp / u->number; + hp_rem += hp[i]; + continue; + } + + /* Heiltrank */ + if (oldpotiontype[P_HEAL]) { + if (get_effect(u, oldpotiontype[P_HEAL]) > 0) { + change_effect(u, oldpotiontype[P_HEAL], -1); + heiltrank = 1; + } + else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) { + i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1); + change_effect(u, oldpotiontype[P_HEAL], 3); + heiltrank = 1; + } + if (heiltrank && (chance(0.50))) { + hp[i] = u->hp / u->number; + hp_rem += hp[i]; + continue; + } + } + dead++; + } + else { + hp_rem += hp[i]; + } + } + + scale_number(u, u->number - dead); + u->hp = hp_rem; + + if (hp != hpstack) { + free(hp); + } + + return dead; +} + +static region *rrandneighbour(region * r) +{ + direction_t i; + region *rc = NULL; + int rr, c = 0; + + /* Nachsehen, wieviele Regionen in Frage kommen */ + + for (i = 0; i != MAXDIRECTIONS; i++) { + c++; + } + /* Zufällig eine auswählen */ + + rr = rng_int() % c; + + /* Durchzählen */ + + c = -1; + for (i = 0; i != MAXDIRECTIONS; i++) { + rc = rconnect(r, i); + c++; + if (c == rr) + break; + } + assert(i != MAXDIRECTIONS); + return rc; +} + +static void +volcano_destruction(region * volcano, region * r, const char *damage) +{ + attrib *a; + unit **up; + int percent = 25, time = 6 + rng_int() % 12; + + rsettrees(r, 2, 0); + rsettrees(r, 1, 0); + rsettrees(r, 0, 0); + + a = a_find(r->attribs, &at_reduceproduction); + if (!a) { + a = a_add(&r->attribs, make_reduceproduction(percent, time)); + } + else { + /* Produktion vierteln ... */ + a->data.sa[0] = (short)percent; + /* Für 6-17 Runden */ + a->data.sa[1] = (short)(a->data.sa[1] + time); + } + + /* Personen bekommen 4W10 Punkte Schaden. */ + + for (up = &r->units; *up;) { + unit *u = *up; + if (u->number) { + int dead = damage_unit(u, damage, true, false); + /* TODO create undead */ + if (dead) { + ADDMSG(&u->faction->msgs, msg_message("volcano_dead", + "unit region dead", u, volcano, dead)); + } + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn", + "region", r)); + } + } + if (u == *up) { + up = &u->next; + } + } + + if (r != volcano) { + ADDMSG(&r->msgs, msg_message("volcanooutbreak", + "regionv regionn", volcano, r)); + } + remove_empty_units_in_region(r); +} + +void volcano_outbreak(region * r) +{ + region *rn; + unit *u; + faction *f; + + for (f = NULL, u = r->units; u; u = u->next) { + if (f != u->faction) { + f = u->faction; + freset(f, FFL_SELECT); + } + } + + /* Zufällige Nachbarregion verwüsten */ + rn = rrandneighbour(r); + volcano_destruction(r, r, "4d10"); + if (rn) { + volcano_destruction(r, rn, "3d10"); + } +} + diff --git a/src/volcano.h b/src/volcano.h new file mode 100644 index 000000000..0521b4292 --- /dev/null +++ b/src/volcano.h @@ -0,0 +1,33 @@ +#pragma once +/* +Copyright (c) 1998-2015, 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. +**/ + +#ifndef H_GC_VOLCANO +#define H_GC_VOLCANO +#ifdef __cplusplus +extern "C" { +#endif + + struct region; + + void volcano_outbreak(struct region * r); + +#ifdef __cplusplus +} +#endif +#endif