diff --git a/src/common/kernel/spell.c b/src/common/kernel/spell.c index 1dd1705b4..829ac17dc 100644 --- a/src/common/kernel/spell.c +++ b/src/common/kernel/spell.c @@ -80,9 +80,6 @@ #include #include /* ----------------------------------------------------------------------- */ -attrib_type at_deathcloud = { - "zauber_todeswolke", NULL, NULL, NULL, NULL, NULL -}; attrib_type at_unitdissolve = { "unitdissolve", NULL, NULL, NULL, a_writedefault, a_readdefault @@ -3311,52 +3308,129 @@ sp_unholypower(castorder *co) * (FARCASTING | REGIONSPELL | TESTRESISTANCE) */ +typedef struct dc_data { + region * r; + unit * mage; + double strength; + int countdown; + boolean active; +} dc_data; + +static void +dc_initialize(struct attrib *a) +{ + dc_data * data = (dc_data *)malloc(sizeof(dc_data)); + a->data.v = data; + data->active = true; +} + +static void +dc_finalize(struct attrib * a) +{ + free(a->data.v); +} + +static int +dc_age(struct attrib * a) +/* age returns 0 if the attribute needs to be removed, !=0 otherwise */ +{ + dc_data * data = (dc_data *)a->data.v; + region * r = data->r; + unit ** up = &r->units; + unit * mage = data->mage; + unit * u; + + if (mage==NULL) { + /* if the mage disappears, so does the spell. */ + return 0; + } + + if (data->active) while (*up!=NULL) { + unit * u = *up; + double damage = data->strength * u->number; + + freset(u->faction, FL_DH); + if (target_resists_magic(mage, u, TYP_UNIT, 0)){ + continue; + } + + /* Reduziert durch Magieresistenz */ + damage *= (1.0 - magic_resistance(u)); + change_hitpoints(u, -(int)damage); + + if (*up==u) up=&u->next; + } + + /* melden, 1x pro Partei */ + for (u = r->units; u; u = u->next ) { + if (!fval(u->faction, FL_DH) ) { + fset(u->faction, FL_DH); + ADDMSG(&u->faction->msgs, msg_message("deathcloud_effect", + "mage region", cansee(u->faction, r, mage, 0) ? mage : NULL, r)); + } + } + + if (!fval(mage->faction, FL_DH)){ + ADDMSG(&mage->faction->msgs, msg_message("deathcloud_effect", + "mage region", mage, r)); + } + + return --data->countdown; +} + +static void +dc_write(const struct attrib * a, FILE* F) +{ + const dc_data * data = (const dc_data *)a->data.v; + fprintf(F, "%d %lf ", data->countdown, data->strength); + write_unit_reference(data->mage, F); + write_region_reference(data->r, F); +} + +static int +dc_read(struct attrib * a, FILE* F) +/* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ +{ + dc_data * data = (dc_data *)a->data.v; + fscanf(F, "%d %lf ", &data->countdown, &data->strength); + read_unit_reference(&data->mage, F); + return read_region_reference(&data->r, F); +} + +attrib_type at_deathcloud = { + "zauber_todeswolke", dc_initialize, dc_finalize, dc_age, dc_write, dc_read +}; + +static attrib * +mk_deathcloud(unit * mage, region * r, double strength, int duration) +{ + attrib * a = a_new(&at_deathcloud); + dc_data * data = (dc_data *)a->data.v; + + data->countdown = duration; + data->r = r; + data->mage = mage; + data->strength = strength; + data->active = false; + return a; +} + static int sp_deathcloud(castorder *co) { - unit *u; - double damage; - region *r = co->rt; - unit *mage = (unit *)co->magician; - int cast_level = co->level; + region *r = co->rt; + unit *mage = (unit *)co->magician; - attrib *a = a_find(r->attribs, &at_deathcloud); + attrib *a = a_find(r->attribs, &at_deathcloud); - if(a){ - report_failure(mage, co->order); - return 0; - } + if (a!=NULL) { + report_failure(mage, co->order); + return 0; + } - for (u = r->units; u; u = u->next){ - if (target_resists_magic(mage, u, TYP_UNIT, 0)){ - continue; - } - /* Jede Person verliert 18 HP */ - damage = 18 * u->number; - /* Reduziert durch Magieresistenz */ - damage *= (1.0 - magic_resistance(u)); - change_hitpoints(u, -(int)damage); - } + a_add(&r->attribs, mk_deathcloud(mage, r, co->force/2, co->level)); - a = a_add(&r->attribs, a_new(&at_deathcloud)); - - /* melden, 1x pro Partei */ - for (u = r->units; u; u = u->next) freset(u->faction, FL_DH); - - for(u = r->units; u; u = u->next ) { - if(!fval(u->faction, FL_DH) ) { - fset(u->faction, FL_DH); - add_message(&u->faction->msgs, new_message(u->faction, - "deathcloud_effect%u:mage%r:region", - cansee(u->faction, r, mage, 0) ? mage:NULL, r)); - } - } - if(!fval(mage->faction, FL_DH)){ - add_message(&mage->faction->msgs, new_message(mage->faction, - "deathcloud_effect%u:mage%r:region", mage, r)); - } - - return cast_level; + return co->level; } void diff --git a/src/common/kernel/unit.c b/src/common/kernel/unit.c index 0ee9a43b6..8cf0897e6 100644 --- a/src/common/kernel/unit.c +++ b/src/common/kernel/unit.c @@ -465,20 +465,17 @@ write_unit_reference(const unit * u, FILE * F) int read_unit_reference(unit ** up, FILE * F) { - char zId[10]; - int i; - fscanf(F, "%s", zId); - if (up==NULL) { - return AT_READ_FAIL; - } - i = atoi36(zId); - if (i==0) { - *up = NULL; - return AT_READ_FAIL; - } - *up = findunit(i); - if (*up==NULL) ur_add((void*)i, (void**)up, resolve_unit); - return AT_READ_OK; + char zId[10]; + int i; + + assert(up!=NULL); + fscanf(F, "%s", zId); + i = atoi36(zId); + assert(i!=0); + + *up = findunit(i); + if (*up==NULL) ur_add((void*)i, (void**)up, resolve_unit); + return AT_READ_OK; } attrib_type at_stealth = { diff --git a/src/common/util/attrib.c b/src/common/util/attrib.c index e4671d3e8..62d815006 100644 --- a/src/common/util/attrib.c +++ b/src/common/util/attrib.c @@ -40,19 +40,22 @@ __at_hashkey(const char* s) void at_register(attrib_type * at) { - attrib_type * find; + attrib_type * find; - at->hashkey = __at_hashkey(at->name); - find = at_hash[at->hashkey % MAXATHASH]; - while (find && at->hashkey!=find->hashkey) find = find->nexthash; - if (find && find==at) { - log_warning(("attribute '%s' was registered more than once\n", at->name)); - return; - } else { - assert(!find || !"hashkey is already in use"); - } - at->nexthash = at_hash[at->hashkey % MAXATHASH]; - at_hash[at->hashkey % MAXATHASH] = at; + if (at->read==NULL) { + log_warning(("registering non-persistent attribute %s.\n", at->name)); + } + at->hashkey = __at_hashkey(at->name); + find = at_hash[at->hashkey % MAXATHASH]; + while (find && at->hashkey!=find->hashkey) find = find->nexthash; + if (find && find==at) { + log_warning(("attribute '%s' was registered more than once\n", at->name)); + return; + } else { + assert(!find || !"hashkey is already in use"); + } + at->nexthash = at_hash[at->hashkey % MAXATHASH]; + at_hash[at->hashkey % MAXATHASH] = at; } static attrib_type * diff --git a/src/eressea/lua/unit.cpp b/src/eressea/lua/unit.cpp index 4889c697d..fc493a6a7 100644 --- a/src/eressea/lua/unit.cpp +++ b/src/eressea/lua/unit.cpp @@ -178,6 +178,11 @@ unit_removespell(unit& u, const spell * sp) } } +static int +unit_hpmax(const unit& u) +{ + return unit_max_hp(&u); +} void bind_unit(lua_State * L) @@ -192,6 +197,8 @@ bind_unit(lua_State * L) .def_readonly("region", &unit::region) .def_readonly("faction", &unit::faction) .def_readonly("id", &unit::no) + .def_readwrite("hp", &unit::hp) + .def("hp_max", &unit_hpmax) .def("get_item", &unit_getitem) .def("add_item", &unit_additem) .def("get_skill", &unit_getskill)