diff --git a/config/creatrs/imp.cfg b/config/creatrs/imp.cfg index 4e636017ad..525ea12c67 100644 --- a/config/creatrs/imp.cfg +++ b/config/creatrs/imp.cfg @@ -34,8 +34,7 @@ Armour = 5 ; Every 26 points of difference between shooter dexterity and victim defence gives ~10% to the odds. ; Also, odds can never get higher than 88% or lower than 12%. Dexterity = 60 -; Wounded fear set to 101 will make creature escape from any combat other than -; protecting heart, or a combat with single creature of the same kind. +; Wounded fear set to 101 will make creature escape from any combat other than protecting heart, or a combat with single creature of the same kind. ; This special value works the same way regardless of creature tendencies. ; Smaller value will make the creature escape if it has less than given percentage of health left. ; 0: never escape, 100: escape even if no health is lost. @@ -92,6 +91,12 @@ DamageToBoulder = 30 ThingSize = 240 400 ; The object the creature will create to use as a lair. Object needs to be configured correctly in objects.cfg too. LairObject = LAIR_IMP +; Defines the kind of creature it will become if it dies of starvation while imprisoned. +; Setting this to NULL will check if the creature has the 'HUMANOID_SKELETON' property and will default to the room creature creation specified in terrain.cfg. +PrisonKind = NULL +; Defines the kind of creature it will become if it dies from torture. +; The same rule applies as above, except it does not consider the 'HUMANOID_SKELETON' property. +TortureKind = NULL ; Creature properties: ; BLEEDS - the creature leaves blood when is hit, slapped, dying or being injured in any way. ; UNAFFECTED_BY_WIND - the creature isn't pushed back by Wind spell. diff --git a/src/config_crtrmodel.c b/src/config_crtrmodel.c index 8517f5e205..4d4e4e920e 100644 --- a/src/config_crtrmodel.c +++ b/src/config_crtrmodel.c @@ -85,6 +85,8 @@ const struct NamedCommand creatmodel_attributes_commands[] = { {"CORPSEVANISHEFFECT", 32}, {"FOOTSTEPPITCH", 33}, {"LAIROBJECT", 34}, + {"PRISONKIND", 35}, + {"TORTUREKIND", 36}, {NULL, 0}, }; @@ -281,6 +283,8 @@ TbBool parse_creaturemodel_attributes_blocks(long crtr_model,char *buf,long len, crstat->flying = false; crstat->can_see_invisible = false; crstat->can_go_locked_doors = false; + crstat->prison_kind = 0; + crstat->torture_kind = 0; crconf->namestr_idx = 0; crconf->model_flags = 0; } @@ -840,6 +844,38 @@ TbBool parse_creaturemodel_attributes_blocks(long crtr_model,char *buf,long len, COMMAND_TEXT(cmd_num), block_buf, config_textname); } break; + case 35: // PRISONKIND + if (get_conf_parameter_single(buf, &pos, len, word_buf, sizeof(word_buf)) > 0) + { + k = get_id(creature_desc, word_buf); + if (k > 0) + { + crstat->prison_kind = k; + n++; + } + } + if (n < 1) + { + CONFWRNLOG("Incorrect value of \"%s\" parameter in [%s] block of %s file.", + COMMAND_TEXT(cmd_num), block_buf, config_textname); + } + break; + case 36: // TORTUREKIND + if (get_conf_parameter_single(buf, &pos, len, word_buf, sizeof(word_buf)) > 0) + { + k = get_id(creature_desc, word_buf); + if (k > 0) + { + crstat->torture_kind = k; + n++; + } + } + if (n < 1) + { + CONFWRNLOG("Incorrect value of \"%s\" parameter in [%s] block of %s file.", + COMMAND_TEXT(cmd_num), block_buf, config_textname); + } + break; case ccr_comment: break; case ccr_endOfFile: diff --git a/src/creature_control.h b/src/creature_control.h index 5311fe4ce7..4acfe9ca42 100644 --- a/src/creature_control.h +++ b/src/creature_control.h @@ -533,6 +533,8 @@ struct CreatureStats { // These stats are not compatible with original DK - they unsigned short good_start_state; unsigned char natural_death_kind; unsigned char swipe_idx; + ThingModel prison_kind; + ThingModel torture_kind; struct CreaturePickedUpOffset creature_picked_up_offset; }; diff --git a/src/creature_states_prisn.c b/src/creature_states_prisn.c index 612ad53bc2..d6d4ee91aa 100644 --- a/src/creature_states_prisn.c +++ b/src/creature_states_prisn.c @@ -314,9 +314,15 @@ CrStateRet creature_in_prison(struct Thing *thing) TbBool prison_convert_creature_to_skeleton(struct Room *room, struct Thing *thing) { + struct CreatureStats* crstat = creature_stats_get_from_thing(thing); struct CreatureControl* cctrl = creature_control_get_from_thing(thing); struct Thing* crthing = INVALID_THING; - long crmodel = get_room_create_creature_model(room->kind); // That normally returns skeleton breed + ThingModel crmodel = crstat->prison_kind; + if ((crmodel > game.conf.crtr_conf.model_count) || (crmodel <= 0)) + { + // If not assigned or is unknown, default to the room creature creation. + crmodel = get_room_create_creature_model(room->kind); + } if (creature_count_below_map_limit(1)) { crthing = create_creature(&thing->mappos, crmodel, room->owner); @@ -334,10 +340,11 @@ TbBool prison_convert_creature_to_skeleton(struct Room *room, struct Thing *thin } else { - WARNLOG("Could not create creature %s to transform %s to due to creature limit", creature_code_name(crmodel),thing_model_name(thing)); + WARNLOG("Could not create creature %s to transform %s to due to creature limit", creature_code_name(crmodel), thing_model_name(thing)); + } + if (creature_model_bleeds(thing->model)) { + create_effect_around_thing(thing, TngEff_Blood5); // TODO CONFIG: make this effect configurable? } - if (creature_model_bleeds(thing->model)) - create_effect_around_thing(thing, TngEff_Blood5); kill_creature(thing, INVALID_THING, -1, CrDed_NoEffects); return !thing_is_invalid(crthing); } @@ -345,12 +352,13 @@ TbBool prison_convert_creature_to_skeleton(struct Room *room, struct Thing *thin TbBool process_prisoner_skelification(struct Thing *thing, struct Room *room) { struct CreatureStats* crstat = creature_stats_get_from_thing(thing); - if ((thing->health >= 0) || (!crstat->humanoid_creature)) { + if ((thing->health >= 0) || ((!crstat->humanoid_creature) && ((crstat->prison_kind > game.conf.crtr_conf.model_count) || (crstat->prison_kind <= 0)))) { + return false; + } + // TODO CONFIG: (?) Allow 'skelification' only if spent specific amount of turns in prison (set it to low value). (?) + if (CREATURE_RANDOM(thing, 101) > game.conf.rules.rooms.prison_skeleton_chance) { return false; } - //TODO CONFIG Allow skeletification only if spent specific amount of turns in prison (set low value) - if (CREATURE_RANDOM(thing, 101) > game.conf.rules.rooms.prison_skeleton_chance) - return false; if (prison_convert_creature_to_skeleton(room, thing)) { if (is_my_player_number(room->owner)) @@ -358,7 +366,7 @@ TbBool process_prisoner_skelification(struct Thing *thing, struct Room *room) output_message(SMsg_PrisonMadeSkeleton, 0, true); } } - return true; //return true even if no skeleton could be created due to creature limit. Otherwise there's a confusing sound message. + return true; // Return true even if no skeleton could be created due to creature limit. Otherwise there's a confusing sound message. } void food_set_wait_to_be_eaten(struct Thing *thing) @@ -430,11 +438,7 @@ TbBool process_prison_food(struct Thing *creatng, struct Room *room) return true; } -/** - * Does a step of being imprisoned. - * Informs if the imprisoning cycle should end. - * @param thing - */ +/* Does a step of being imprisoned. * Informs if the imprisoning cycle should end. * @param thing */ CrCheckRet process_prison_function(struct Thing *creatng) { struct Room* room = get_room_creature_works_in(creatng); @@ -450,28 +454,29 @@ CrCheckRet process_prison_function(struct Thing *creatng) { return CrCkRet_Deleted; } - else if ((creatng->health < 0) && (!crstat->humanoid_creature)) - { + else if ((creatng->health < 0) && ((!crstat->humanoid_creature) && ((crstat->prison_kind > game.conf.crtr_conf.model_count) || (crstat->prison_kind <= 0)))) + { if (is_my_player_number(room->owner)) { output_message(SMsg_PrisonersStarving, MESSAGE_DELAY_STARVING, 1); } } struct CreatureControl* cctrl = creature_control_get_from_thing(creatng); - if ((cctrl->instance_id == CrInst_NULL) && process_prison_food(creatng, room) ) + if ((cctrl->instance_id == CrInst_NULL) && process_prison_food(creatng, room)) return CrCkRet_Continue; - // Breaking from jail is only possible once per some amount of turns, - // and only if creature sits in jail for long enough + // Breaking from jail is only possible once per some amount of turns, and only if creature sits in jail for long enough. if (((game.play_gameturn % game.conf.rules.rooms.time_between_prison_break) == 0) && (game.play_gameturn > cctrl->imprison.start_gameturn + game.conf.rules.rooms.time_in_prison_without_break)) { - // Check the base jail break condition - whether prison touches enemy land + // Check the base jail break condition - whether prison touches enemy land. if (jailbreak_possible(room, creatng->owner) && (CREATURE_RANDOM(creatng, 100) < game.conf.rules.rooms.prison_break_chance)) { - if (is_my_player_number(room->owner)) + if (is_my_player_number(room->owner)) { output_message(SMsg_PrisonersEscaping, 40, true); - else if (is_my_player_number(room->owner)) + } + else if (is_my_player_number(room->owner)) { output_message(SMsg_CreatrFreedPrison, 40, true); + } set_start_state(creatng); return CrCkRet_Continue; } diff --git a/src/creature_states_tortr.c b/src/creature_states_tortr.c index 534d004ac8..53e11c4c7e 100644 --- a/src/creature_states_tortr.c +++ b/src/creature_states_tortr.c @@ -273,14 +273,20 @@ CrCheckRet process_kinky_function(struct Thing *thing) void convert_creature_to_ghost(struct Room *room, struct Thing *thing) { - int crmodel = get_room_create_creature_model(room->kind); + struct CreatureStats* crstat = creature_stats_get_from_thing(thing); + ThingModel crmodel = crstat->torture_kind; + if ((crmodel > game.conf.crtr_conf.model_count) || (crmodel <= 0)) + { + // If not assigned or is unknown, default to the room creature creation. + crmodel = get_room_create_creature_model(room->kind); + } struct Thing* newthing = INVALID_THING; if (creature_count_below_map_limit(1)) { newthing = create_creature(&thing->mappos, crmodel, room->owner); if (thing_is_invalid(newthing)) { - ERRORLOG("Couldn't create creature %s in %s room",creature_code_name(crmodel),room_code_name(room->kind)); + ERRORLOG("Couldn't create creature %s in %s room", creature_code_name(crmodel), room_code_name(room->kind)); return; } } else @@ -290,8 +296,9 @@ void convert_creature_to_ghost(struct Room *room, struct Thing *thing) struct CreatureControl* cctrl = creature_control_get_from_thing(thing); struct CreatureControl* newcctrl = creature_control_get_from_thing(newthing); init_creature_level(newthing, cctrl->explevel); - if (creature_model_bleeds(thing->model)) - create_effect_around_thing(newthing, TngEff_Blood5); + if (creature_model_bleeds(thing->model)) { + create_effect_around_thing(newthing, TngEff_Blood5); // TODO CONFIG: make this effect configurable? + } set_start_state(newthing); strcpy(newcctrl->creature_name, cctrl->creature_name); kill_creature(thing, INVALID_THING, -1, CrDed_NoEffects|CrDed_DiedInBattle); @@ -299,8 +306,9 @@ void convert_creature_to_ghost(struct Room *room, struct Thing *thing) if (!dungeon_invalid(dungeon)) { dungeon->lvstats.ghosts_raised++; } - if (is_my_player_number(room->owner)) + if (is_my_player_number(room->owner)) { output_message(SMsg_TortureMadeGhost, 0, true); + } } void convert_tortured_creature_owner(struct Thing *creatng, PlayerNumber new_owner) diff --git a/src/lvl_script_commands.c b/src/lvl_script_commands.c index ee1fbab5cd..462e44615f 100644 --- a/src/lvl_script_commands.c +++ b/src/lvl_script_commands.c @@ -2818,7 +2818,7 @@ static void set_creature_configuration_check(const struct ScriptLine* scline) } else if (creatvar == 34) // LAIROBJECT { - if (parameter_is_number(scline->tp[2])) //support name or number for lair object + if (parameter_is_number(scline->tp[2])) // Support name or number for lair object. { value1 = atoi(scline->tp[2]); } @@ -2827,6 +2827,17 @@ static void set_creature_configuration_check(const struct ScriptLine* scline) value1 = get_id(object_desc, scline->tp[2]); } } + else if ((creatvar == 35) || (creatvar == 36)) // PRISONKIND or TORTUREKIND + { + if (parameter_is_number(scline->tp[2])) // Support name or number for prison kind or torture kind. + { + value1 = atoi(scline->tp[2]); + } + else + { + value1 = get_id(creature_desc, scline->tp[2]); + } + } else { value1 = atoi(scline->tp[2]); @@ -3107,6 +3118,12 @@ static void set_creature_configuration_process(struct ScriptContext* context) crstat->lair_object = value; } break; + case 35: // PRISONKIND + crstat->prison_kind = value; + break; + case 36: // TORTUREKIND + crstat->torture_kind = value; + break; case ccr_comment: break; case ccr_endOfFile: