diff --git a/config/fxdata/rules.cfg b/config/fxdata/rules.cfg index 33bb284984..c53d771101 100644 --- a/config/fxdata/rules.cfg +++ b/config/fxdata/rules.cfg @@ -28,6 +28,19 @@ GemEffectiveness = 17 PayDayGap = 10000 ; How fast pay day comes percentage. PayDaySpeed = 100 +; Amount of paydays the creatures can be paid in advance. +; 0 = Creatures goes always to the treasure room. +PaydayAdvanced = 5 +; Amount of paydays the player can be in debt to creatures. 0/255 +; 0 = Creatures ignores all paydays +PaydayOwed = 5 +; (Orginal Behaviour) Creatures will accept any amount of gold given from hand (or pocket if enabled) 0/255 +; to skip current and any payday in advance. 0/1 +AcceptPartialPayday = 1 +; Creatures will carry gold in their pockets when manually given by the player. 0/1 +PocketGold = 0 +; Creatures will first use any gold in their pockets for their payday before going to the treasury. 0/1 +TakePayFromPocket = 0 ; How many game turns between the heart recovering health. DungeonHeartHealTime = 8 ; How much health the heart recovers. Or loses when negative. @@ -72,7 +85,7 @@ EasterEggSpeechInterval = 20000 ; STUN_FRIENDLY_UNITS - Infighting with imprisonment on will not kill your creatures. ; PASSIVE_NEUTRALS - Neutral creatures placed in prison or torture room wander out. ; NEUTRAL_TORTURE_CONVERTS - Neutral torture rooms convert creatures into neutral creatures. -PreserveClassicBugs = +PreserveClassicBugs = [computer] ; Maximum health percentage when creatures are considered to be put to temple to cure of disease. diff --git a/src/config_rules.c b/src/config_rules.c index a2b35e96ed..9f14a8f56b 100644 --- a/src/config_rules.c +++ b/src/config_rules.c @@ -93,9 +93,13 @@ const struct NamedField rules_game_named_fields[] = { {"GLOBALAMBIENTLIGHT", &game.conf.rules.game.global_ambient_light, var_type(game.conf.rules.game.global_ambient_light ), LONG_MIN, LONG_MAX}, {"LIGHTENABLED", &game.conf.rules.game.light_enabled, var_type(game.conf.rules.game.light_enabled ), 0, 1}, {"MAPCREATURELIMIT", &game.conf.rules.game.creatures_count, var_type(game.conf.rules.game.creatures_count ), 0, CREATURES_COUNT-2}, + {"PAYDAYADVANCED", &game.conf.rules.game.max_paydays_advanced, var_type(game.conf.rules.game.max_paydays_advanced ), 0, UCHAR_MAX}, + {"PAYDAYOWED", &game.conf.rules.game.max_paydays_owed, var_type(game.conf.rules.game.max_paydays_owed ), 0, UCHAR_MAX}, + {"ACCEPTPARTIALPAYDAY", &game.conf.rules.game.accept_partial_payday, var_type(game.conf.rules.game.accept_partial_payday ), 0, 1}, + {"POCKETGOLD", &game.conf.rules.game.pocket_gold, var_type(game.conf.rules.game.pocket_gold ), 0, 1}, + {"TAKEPAYFROMPOCKET", &game.conf.rules.game.take_pay_from_pocket, var_type(game.conf.rules.game.take_pay_from_pocket ), 0, 1}, {NULL, NULL, 0, 0, 0}, }; - // Special cases rules_game. const struct NamedCommand rules_game_commands[] = { {"PRESERVECLASSICBUGS", 1}, @@ -292,6 +296,11 @@ static void set_defaults() game.conf.rules.game.torture_training_cost = 100; game.conf.rules.game.torture_scavenging_cost = 100; game.conf.rules.game.creatures_count = 255; + game.conf.rules.game.max_paydays_advanced = 5; + game.conf.rules.game.max_paydays_owed = 5; + game.conf.rules.game.accept_partial_payday = true; + game.conf.rules.game.pocket_gold = false; + game.conf.rules.game.take_pay_from_pocket = false; // Creature block. game.conf.rules.creature.recovery_frequency = 10; game.conf.rules.creature.fight_max_hate = 200; @@ -616,7 +625,7 @@ static void mark_cheaper_diggers_sacrifice(void) struct SacrificeRecipe* sac = &game.conf.rules.sacrifices.sacrifice_recipes[i]; if (sac->action == SacA_None) continue; - if (((sac->action == SacA_PosUniqFunc) && (sac->param == UnqF_CheaperImp)) + if (((sac->action == SacA_PosUniqFunc) && (sac->param == UnqF_CheaperImp)) || ((sac->action == SacA_NegUniqFunc) && (sac->param == UnqF_CostlierImp))) { if ((sac->victims[1] == 0) && (game.conf.rules.sacrifices.cheaper_diggers_sacrifice_model == 0)) { diff --git a/src/config_rules.h b/src/config_rules.h index 80aa703734..921111b41e 100644 --- a/src/config_rules.h +++ b/src/config_rules.h @@ -104,6 +104,11 @@ struct GameRulesConfig { long global_ambient_light; TbBool light_enabled; unsigned short creatures_count; + unsigned char max_paydays_advanced; + unsigned char max_paydays_owed; + TbBool accept_partial_payday; + TbBool pocket_gold; + TbBool take_pay_from_pocket; }; struct ComputerRulesConfig { diff --git a/src/creature_control.h b/src/creature_control.h index e9c53ec07e..7475ed16e1 100644 --- a/src/creature_control.h +++ b/src/creature_control.h @@ -165,6 +165,7 @@ struct CreatureControl { unsigned char thought_bubble_display_timer; unsigned char paydays_owed; char paydays_advanced; + GoldAmount paid_wage; long annoy_untrained_turn; unsigned long last_roar_turn; /** The game enumerates the elements of annoyance array periodically and looks for the highest value. diff --git a/src/creature_states.c b/src/creature_states.c index 58a8e58f46..6dcb0011c6 100644 --- a/src/creature_states.c +++ b/src/creature_states.c @@ -821,7 +821,7 @@ TbBool creature_is_called_to_arms(const struct Thing *thing) TbBool creature_is_taking_salary_activity(const struct Thing *thing) { CrtrStateId crstate = get_creature_state_besides_move(thing); - if ((crstate == CrSt_CreatureWantsSalary) || (crstate == CrSt_CreatureTakeSalary)) + if ((crstate == CrSt_CreatureWantsSalary) || (crstate == CrSt_CreatureTakeSalary) || (crstate == CrSt_CreatureWaitAtTreasureRoomDoor)) return true; return false; } @@ -3018,6 +3018,8 @@ short creature_pick_up_spell_to_steal(struct Thing *creatng) short creature_take_salary(struct Thing *creatng) { + GoldAmount salary = calculate_correct_creature_pay(creatng); + struct CreatureControl* cctrl = creature_control_get_from_thing(creatng); TRACE_THING(creatng); SYNCDBG(18,"Starting"); if (!thing_is_on_own_room_tile(creatng)) @@ -3033,7 +3035,11 @@ short creature_take_salary(struct Thing *creatng) internal_set_thing_state(creatng, CrSt_CreatureWantsSalary); return 1; } - GoldAmount salary = calculate_correct_creature_pay(creatng); + // Creature take salary first out of her own pocket + if(game.conf.rules.game.take_pay_from_pocket || !game.conf.rules.game.accept_partial_payday){ + salary -= cctrl->paid_wage; + cctrl->paid_wage = 0; + } GoldAmount received = take_money_from_dungeon(creatng->owner, salary, 0); if (received < 1) { ERRORLOG("The %s index %d has used capacity %d but no gold for %s salary",room_code_name(room->kind), @@ -3042,15 +3048,20 @@ short creature_take_salary(struct Thing *creatng) return 1; } else { - struct CreatureControl* cctrl = creature_control_get_from_thing(creatng); if (cctrl->paydays_owed > 0) { cctrl->paydays_owed--; } if ((dungeon->total_money_owned >= salary) && (cctrl->paydays_advanced < 0)) //If the creature has missed payday, and there is money again, time to pay up. { - cctrl->paydays_owed++; - cctrl->paydays_advanced++; + if (cctrl->paydays_owed < game.conf.rules.game.max_paydays_owed) + { + cctrl->paydays_owed++; + } + if (cctrl->paydays_advanced < game.conf.rules.game.max_paydays_advanced) + { + cctrl->paydays_advanced++; + } } } set_start_state(creatng); @@ -4943,6 +4954,78 @@ long creature_setup_head_for_treasure_room_door(struct Thing *creatng, struct Ro return 0; } +/** + * @brief + * Used if take_pay_from_pocket rule is activated + * + * Attempts to deduct the creature's salary from its carried gold. + * + * - If partial paydays are allowed, the function subtracts as much as possible + * from the creature's pocket. + * + * - Otherwise, it tries to cover the full salary + * from the pocket and, if not enough, from the dungeon. + * @param creatng + * @return TbBool Returns true if enough gold is taken from the creature to handle the entaire payday + */ +TbBool process_custom_salary(struct Thing *creatng) +{ + struct CreatureControl* cctrl = creature_control_get_from_thing(creatng); + // Calculate the correct salary for the creature. + GoldAmount salary = calculate_correct_creature_pay(creatng); + // Subtract any already given gold from the salary + salary -= cctrl->paid_wage; + struct Dungeon* dungeon = get_dungeon(creatng->owner); + if(creatng->creature.gold_carried > 0) + { + //Creature has enough gold to cover the salary or partial paydays are allowed. + if((creatng->creature.gold_carried >= salary) || (game.conf.rules.game.accept_partial_payday)) + { + //Reduce the number of paydays owed + cctrl->paydays_owed--; + //Reset already given gold + cctrl->paid_wage = 0; + //Visual effect + struct Thing* efftng; + if(game.conf.rules.game.accept_partial_payday && (salary > creatng->creature.gold_carried)) + { + efftng = create_price_effect(&creatng->mappos, creatng->owner, creatng->creature.gold_carried); + } + else + { + efftng = create_price_effect(&creatng->mappos, creatng->owner, salary); + } + //Take the salary from the creature pocket + creatng->creature.gold_carried -= salary; + //Ensure that the creature's gold carried does not drop below zero. + if (creatng->creature.gold_carried < 0) + { + creatng->creature.gold_carried = 0; + } + set_start_state(creatng); + //Play sound effect + thing_play_sample(efftng, 32, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); + dungeon->lvstats.salary_cost += salary; + return 1; + } + //Continue to take the remaining salary from the dungeon + else + { + //Add carried gold to already paid gold + cctrl->paid_wage += creatng->creature.gold_carried; + //Visual effect + struct Thing* efftng = create_price_effect(&creatng->mappos, creatng->owner, creatng->creature.gold_carried); + //Sound effect + thing_play_sample(efftng, 32, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); + //Reset carried gold + creatng->creature.gold_carried = 0; + //Creature continues to try to take the salary from the dungeon + return 0; + } + } + return 0; +} + long process_creature_needs_a_wage(struct Thing *creatng, const struct CreatureStats *crstat) { struct CreatureControl* cctrl = creature_control_get_from_thing(creatng); @@ -4952,6 +5035,14 @@ long process_creature_needs_a_wage(struct Thing *creatng, const struct CreatureS if (creature_is_taking_salary_activity(creatng)) { return 1; } + // rule activated + if(game.conf.rules.game.take_pay_from_pocket) + { + if(process_custom_salary(creatng)) + { + return 1; + } + } if (!can_change_from_state_to(creatng, creatng->active_state, CrSt_CreatureWantsSalary)) { return 0; } @@ -5122,10 +5213,17 @@ long anger_process_creature_anger(struct Thing *creatng, const struct CreatureSt { if ((dungeon->total_money_owned >= dungeon->creatures_total_backpay) && !room_is_invalid(room)) { - cctrl->paydays_advanced++; + if (cctrl->paydays_advanced < game.conf.rules.game.max_paydays_advanced) + { + cctrl->paydays_advanced++; + } if (cctrl->paydays_owed < SCHAR_MAX) { - cctrl->paydays_owed++; // if there's enough money to pay, go to treasure room now, instead of complaining + // if there's enough money to pay, go to treasure room now, instead of complaining + if (cctrl->paydays_owed < game.conf.rules.game.max_paydays_owed) + { + cctrl->paydays_owed++; + } } } else diff --git a/src/creature_states.h b/src/creature_states.h index c077cfe57c..0321e7d016 100644 --- a/src/creature_states.h +++ b/src/creature_states.h @@ -343,6 +343,7 @@ SubtlCodedCoords find_position_around_in_room(const struct Coord3d *pos, PlayerN void remove_health_from_thing_and_display_health(struct Thing *thing, HitPoints delta); TbBool process_creature_hunger(struct Thing *thing); +TbBool process_custom_salary(struct Thing *creatng); void process_person_moods_and_needs(struct Thing *thing); TbBool restore_creature_flight_flag(struct Thing *creatng); TbBool attempt_to_destroy_enemy_room(struct Thing *thing, MapSubtlCoord stl_x, MapSubtlCoord stl_y); diff --git a/src/main.cpp b/src/main.cpp index 96d0a2c880..9d3fb3cb25 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2335,6 +2335,10 @@ void count_players_creatures_being_paid(int *creatures_count) } else { cctrl->paydays_owed++; + if (cctrl->paydays_owed > game.conf.rules.game.max_paydays_owed) + { + cctrl->paydays_owed = game.conf.rules.game.max_paydays_owed; + } creatures_count[thing->owner]++; } } diff --git a/src/power_hand.c b/src/power_hand.c index 0d769f844b..6bc83d2b5b 100644 --- a/src/power_hand.c +++ b/src/power_hand.c @@ -636,7 +636,7 @@ void draw_power_hand(void) if (crstat->transparency_flags == TRF_Transpar_8) { lbDisplay.DrawFlags |= Lb_SPRITE_TRANSPAR8; - lbDisplay.DrawFlags &= ~Lb_TEXT_UNDERLNSHADOW; + lbDisplay.DrawFlags &= ~Lb_TEXT_UNDERLNSHADOW; } else if (crstat->transparency_flags == TRF_Transpar_4) { @@ -833,34 +833,159 @@ void drop_gold_coins(const struct Coord3d *pos, long value, long plyr_idx) player->hand_busy_until_turn = game.play_gameturn + 16; } } +/** + * @brief Processes payday advances from hand gold. + */ +void process_payday_advances(GoldAmount salary, struct Thing *creatng, struct CreatureControl *cctrl, struct CreatureStats *crstat) +{ + GoldAmount complete_cost = 0; + int paid = cctrl->paid_wage / salary; + //ensure that the number of advanced paydays does not exceed the maximum + if (cctrl->paydays_advanced + paid > game.conf.rules.game.max_paydays_advanced) + { + cctrl->paydays_advanced = game.conf.rules.game.max_paydays_advanced; + } + else + { + cctrl->paydays_advanced += paid; + } + complete_cost = paid * salary; + // reduce the amount of gold for all paid advanced paydays + cctrl->paid_wage -= complete_cost; + //if pocket rule is active, reduce the amount of gold in the pocket + if(game.conf.rules.game.pocket_gold) + { + creatng->creature.gold_carried -= complete_cost; + } +} + +/** + * @brief Add gold from hand to the creature's pocket if the pocket gold rule is active. + */ +GoldAmount handle_pocket_gold_rule(GoldAmount tribute, struct Thing* creatng, struct CreatureStats* crstat, struct CreatureControl* cctrl) +{ + GoldAmount fill_space = crstat->gold_hold - creatng->creature.gold_carried; + //fill the pockets + if(tribute < fill_space) + { + creatng->creature.gold_carried += tribute; + } + //pocket ist full + else + { + creatng->creature.gold_carried = crstat->gold_hold; + return (tribute -= fill_space); + } + return 0; +} + +/** + * @brief Processes the gold dropped on a creature. + * + * This function manages gold dropped on creatures both during and outside of a payday. + * It process configuration settings for pocket gold, partial payments and limits the advanced paydays. + * + * @param salary The salary to be paid. + * @param tribute The incoming tribute. + * @param cctrl Pointer to the CreatureControl structure. + * @param during_payday Indicates whether the function is called during a payday. + * + * @ + */ +GoldAmount creature_get_handgold(GoldAmount salary, GoldAmount tribute, struct Thing* creatng, struct CreatureStats* crstat, struct CreatureControl* cctrl, TbBool during_payday) +{ + GoldAmount remainingTribute = 0; + if (!game.conf.rules.game.accept_partial_payday) + { + //if rule active + //add tribute to the gold carried by the creature + if(game.conf.rules.game.pocket_gold){ + remainingTribute = handle_pocket_gold_rule(tribute, creatng, crstat, cctrl); + + // paid_wage equals the amount of gold in the pocket + cctrl->paid_wage = creatng->creature.gold_carried; + } + // pocket rule deactivated + else + { + // add tribute to the paid wage + cctrl->paid_wage += tribute; + } + // process the tribute during payday + if (during_payday && cctrl->paid_wage >= salary) + { + // rule activated + if(game.conf.rules.game.take_pay_from_pocket) + { + process_custom_salary(creatng); + } + else + { + // reduce paydays owed if during payday and sufficient wage is paid + cctrl->paydays_owed--; + } + process_payday_advances(salary, creatng, cctrl, crstat); + + } + else if (cctrl->paid_wage >= salary) + { + process_payday_advances(salary, creatng, cctrl, crstat); + } + } + + else // accept_partial_payday is true + { + //if pocket rule active, add tribute to the gold carried by the creature + if(game.conf.rules.game.pocket_gold){ + remainingTribute = handle_pocket_gold_rule(tribute, creatng, crstat, cctrl); + creatng->creature.gold_carried = 0; + } + if (during_payday) + { + // suring payday, decrement paydays owed + cctrl->paydays_owed--; + } + else + { + // not during payday, increment paydays_advanced if possible + if (cctrl->paydays_advanced < game.conf.rules.game.max_paydays_advanced) + { + cctrl->paydays_advanced++; + } + } + } + return remainingTribute; +} long gold_being_dropped_on_creature(long plyr_idx, struct Thing *goldtng, struct Thing *creatng) { - struct CreatureControl *cctrl; + struct CreatureControl *cctrl = creature_control_get_from_thing(creatng); struct Coord3d pos; - TbBool taking_salary; - taking_salary = false; + struct CreatureStats* crstat = creature_stats_get_from_thing(creatng); + //actuel amount of gold in hand + GoldAmount tribute = goldtng->valuable.gold_stored; + GoldAmount salary = calculate_correct_creature_pay(creatng); + if (salary < 1) // we devide by this number later on + { + salary = 1; + } pos.x.val = creatng->mappos.x.val; pos.y.val = creatng->mappos.y.val; pos.z.val = creatng->mappos.z.val; + //gold falls from the hand pos.z.val = get_ceiling_height_at(&pos); - if (creature_is_taking_salary_activity(creatng)) + //creature is in need of a salary (to ensure all states are affected) + TbBool during_payday = (cctrl->paydays_owed > 0); // creature_take_salary + //process the gold dropped on the creature, considering the rules + GoldAmount remainingTribute = creature_get_handgold(salary, tribute, creatng, crstat, cctrl, during_payday); + if (during_payday && cctrl->paydays_owed == 0) { - cctrl = creature_control_get_from_thing(creatng); - if (cctrl->paydays_owed > 0) - cctrl->paydays_owed--; + // end payday states set_start_state(creatng); - taking_salary = true; - } - GoldAmount salary; - salary = calculate_correct_creature_pay(creatng); - if (salary < 1) // we devide by this number later on - { - salary = 1; } - long tribute; - tribute = goldtng->valuable.gold_stored; + //visual effect for falling gold coins drop_gold_coins(&pos, 0, plyr_idx); + //sound effects if (tribute >= salary) { thing_play_sample(creatng, 34, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); @@ -873,20 +998,47 @@ long gold_being_dropped_on_creature(long plyr_idx, struct Thing *goldtng, struct { thing_play_sample(creatng, 32, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS/2); } - if ( !taking_salary ) + long happiness = 0; + //pocket_gold rule is active + if(game.conf.rules.game.pocket_gold) { - cctrl = creature_control_get_from_thing(creatng); - if (cctrl->paydays_advanced < SCHAR_MAX) { - cctrl->paydays_advanced++; + //if the tribute doesn't fit entirely in the pocket + if (remainingTribute > 0) + { + // calculate the portion of tribute that was successfully added to the pocket + long usedTrib = tribute - remainingTribute; + // calculate the base happiness value based on the ratio of tribute to salary + long baseHap = crstat->annoy_got_wage / salary; + // calculate single happiness from the tribute that fits into the pocket + long hapFit = baseHap * usedTrib; + // calculate double happiness from the remaining tribute + long hapRem = baseHap * remainingTribute * 2; + // sum both happiness contributions + happiness = hapFit + hapRem; + // apply the calculated happiness to the creature + anger_apply_anger_to_creature_all_types(creatng, happiness); + } + // if the entire tribute fits into the creature's pocket + else + { + // calculate single happiness from the tribute that fits into the pocket + happiness = crstat->annoy_got_wage * tribute / salary; + anger_apply_anger_to_creature_all_types( creatng, happiness); } } - struct CreatureStats *crstat; - crstat = creature_stats_get_from_thing(creatng); - anger_apply_anger_to_creature_all_types(creatng, (crstat->annoy_got_wage * tribute / salary * 2)); + //default/no pocket_gold rule + else + { + // calculate double happiness from the entaire tribute + happiness = crstat->annoy_got_wage * tribute / salary * 2; + anger_apply_anger_to_creature_all_types(creatng, happiness); + } + //classic_bug handling if (game.conf.rules.game.classic_bugs_flags & ClscBug_FullyHappyWithGold) { anger_set_creature_anger_all_types(creatng, 0); } + //creature start celebrating animation if (can_change_from_state_to(creatng, get_creature_state_besides_interruptions(creatng), CrSt_CreatureBeHappy)) { if (external_set_thing_state(creatng, CrSt_CreatureBeHappy)) { @@ -1521,7 +1673,7 @@ TbBool can_drop_thing_here(MapSubtlCoord stl_x, MapSubtlCoord stl_y, PlayerNumbe return true; } } - } + } } else { diff --git a/src/thing_creature.c b/src/thing_creature.c index 584c24518c..02d58205f1 100644 --- a/src/thing_creature.c +++ b/src/thing_creature.c @@ -1570,7 +1570,7 @@ void terminate_all_actives_damage_over_time_spell_effects(struct Thing *thing) } } -/* Clears spell effect on a thing. +/* Clears spell effect on a thing. * It first checks for an active spell match and terminates the associated spell. * If no exact match is found, it clears only the flag without affecting others. * This ensures that spells with multiple flags remain intact. @@ -2377,6 +2377,8 @@ TbBool creature_pick_up_interesting_object_laying_nearby(struct Thing *creatng) if (object_is_gold_laying_on_ground(tgthing)) { struct CreatureStats* crstat = creature_stats_get_from_thing(creatng); + GoldAmount salary = crstat->pay; + GoldAmount gold = tgthing->valuable.gold_stored; if (tgthing->valuable.gold_stored > 0) { if (creatng->creature.gold_carried < crstat->gold_hold) @@ -2385,20 +2387,19 @@ TbBool creature_pick_up_interesting_object_laying_nearby(struct Thing *creatng) { long k = crstat->gold_hold - creatng->creature.gold_carried; creatng->creature.gold_carried += k; - tgthing->valuable.gold_stored -= k; + gold -= k; } else { creatng->creature.gold_carried += tgthing->valuable.gold_stored; delete_thing_structure(tgthing, 0); } - thing_play_sample(creatng, 32, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); - } + thing_play_sample(creatng, 32, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); } + anger_apply_anger_to_creature(creatng, crstat->annoy_got_wage * gold / salary, AngR_NotPaid, 1); } else { ERRORLOG("GoldPile with no gold!"); delete_thing_structure(tgthing, 0); } - anger_apply_anger_to_creature(creatng, crstat->annoy_got_wage, AngR_NotPaid, 1); return true; } if (thing_can_be_eaten(tgthing) && creature_able_to_eat(creatng)) @@ -3142,7 +3143,7 @@ struct Thing* cause_creature_death(struct Thing *thing, CrDeathFlags flags) remove_parent_thing_from_things_in_list(&game.thing_lists[TngList_Shots],thing->index); ThingModel crmodel = thing->model; struct CreatureStats* crstat = creature_stats_get_from_thing(thing); - if (!thing_exists(thing)) + if (!thing_exists(thing)) { set_flag(flags,CrDed_NoEffects); }