Skip to content

Commit

Permalink
Fixed growing up creatures not cheering + refactor (#3821)
Browse files Browse the repository at this point in the history
also allows for a random growup level
  • Loading branch information
walt253 authored Jan 23, 2025
1 parent b959335 commit ad1fafb
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 94 deletions.
2 changes: 1 addition & 1 deletion config/creatrs/imp.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ PowersLevelRequired = 1 1 3 0 0 0 0 0 0 10
; Training values required to reach higher creature levels.
LevelsTrainValues = 2500 3500 5000 6500 8500 10500 13000 16000 20000
; Growing beyond max level - training value, new creature kind and its level. Example: 20000 FLY 5.
; Accepts ANY_CREATURE for random but evil will stay evil and good will stay good.
; Accepts ANY_CREATURE for random but evil will stay evil and good will stay good. Set level to 0 to randomise it.
GrowUp = 0 NULL 0
; Gaining experience from sleeping - slab required near lair and amount of experience.
; It is enough if one slab of given type exists anywhere next to the room slab, and all creatures inside get the bonus.
Expand Down
10 changes: 5 additions & 5 deletions src/config_creature.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,11 @@ void check_and_auto_fix_stats(void)
}
if (crstat->grow_up > 0)
{
if ( (crstat->grow_up_level < 1) || (crstat->grow_up_level > CREATURE_MAX_LEVEL) )
{
ERRORLOG("Creature model %d (%s) GrowUp & GrowUpLevel invalid - Fixing", (int)model, creature_code_name(model));
crstat->grow_up_level = 1;
}
if (crstat->grow_up_level > CREATURE_MAX_LEVEL)
{
ERRORLOG("Creature model %d (%s) GrowUp & GrowUpLevel invalid - Fixing", (int)model, creature_code_name(model));
crstat->grow_up_level = CREATURE_MAX_LEVEL;
}
}
if (crstat->rebirth > CREATURE_MAX_LEVEL)
{
Expand Down
2 changes: 1 addition & 1 deletion src/creature_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ struct CreatureStats { // These stats are not compatible with original DK - they
unsigned long to_level[CREATURE_MAX_LEVEL];
unsigned char base_speed;
ThingModel grow_up;
unsigned char grow_up_level;
CrtrExpLevel grow_up_level;
TbBool entrance_force;
short max_turning_speed;
short base_eye_height;
Expand Down
194 changes: 107 additions & 87 deletions src/thing_creature.c
Original file line number Diff line number Diff line change
Expand Up @@ -6284,111 +6284,29 @@ void transfer_creature_data_and_gold(struct Thing *oldtng, struct Thing *newtng)

long update_creature_levels(struct Thing *thing)
{
SYNCDBG(18,"Starting");
struct CreatureControl *cctrl = creature_control_get_from_thing(thing);
if (!cctrl->exp_level_up)
{
return 0;
}
cctrl->exp_level_up = false;
// If a creature is not on highest level, just update the level
// If a creature is not on highest level, just update the level.
if (cctrl->explevel+1 < CREATURE_MAX_LEVEL)
{
remove_creature_score_from_owner(thing); // the opposite is in set_creature_level()
set_creature_level(thing, cctrl->explevel+1);
return 1;
}
// If it is highest level, maybe we should transform the creature?
struct CreatureStats* crstat = creature_stats_get_from_thing(thing);
if (crstat->grow_up == 0) {
return 0;
}
// Transforming
struct CreatureModelConfig* oriconf = &game.conf.crtr_conf.model[thing->model];
ThingModel model = crstat->grow_up;
if (model == CREATURE_NOT_A_DIGGER)
{
while (1) {
model = GAME_RANDOM(game.conf.crtr_conf.model_count) + 1;

if (model >= game.conf.crtr_conf.model_count) {
continue;
}

// Exclude growing up into same creature, spectators and diggers
if (model == thing->model) {
continue;
}
struct CreatureModelConfig* crconf = &game.conf.crtr_conf.model[model];
if ((crconf->model_flags & CMF_IsSpectator) != 0) {
continue;
}
if ((crconf->model_flags & CMF_IsSpecDigger) != 0) {
continue;
}

//evil growup evil, good growup good
if (((crconf->model_flags & CMF_IsEvil) == 0) && ((oriconf->model_flags & CMF_IsEvil) == 0))
{
break;
}
if ((crconf->model_flags & CMF_IsEvil) && (oriconf->model_flags & CMF_IsEvil))
{
break;
}
}
}
if (!creature_count_below_map_limit(1))
// If it is highest level, check if the creature can grow up.
struct CreatureStats *crstat = creature_stats_get_from_thing(thing);
if (crstat->grow_up == 0)
{
WARNLOG("Could not create creature to transform %s to due to creature limit", thing_model_name(thing));
return 0;
}
struct Thing* newtng = create_creature(&thing->mappos, model, thing->owner);
if (thing_is_invalid(newtng))
if (!grow_up_creature(thing, crstat->grow_up, crstat->grow_up_level))
{
ERRORLOG("Could not create creature to transform %s to",thing_model_name(thing));
return 0;
}
set_creature_level(newtng, crstat->grow_up_level-1);
transfer_creature_data_and_gold(thing, newtng);// Transfer the blood type, creature name, kill count, joined age and carried gold to the new creature.
update_creature_health_to_max(newtng);
cctrl = creature_control_get_from_thing(thing);
cctrl->countdown = 50;
external_set_thing_state(newtng, CrSt_CreatureBeHappy);
struct PlayerInfo* player = get_player(thing->owner);
// Switch control if this creature is possessed
if (is_thing_directly_controlled(thing))
{
leave_creature_as_controller(player, thing);
control_creature_as_controller(player, newtng);
}
if (is_thing_passenger_controlled(thing))
{
leave_creature_as_passenger(player, thing);
control_creature_as_passenger(player, newtng);
}
// If not directly nor passenger controlled, but still player is doing something with it
if (thing->index == player->controlled_thing_idx)
{
set_selected_creature(player, newtng);
}
remove_creature_score_from_owner(thing); // kill_creature() doesn't call this
if (thing_is_picked_up_by_player(thing,thing->owner))
{
struct Dungeon* dungeon = get_dungeon(thing->owner);
short i = get_thing_in_hand_id(thing, thing->owner);
if (i >= 0)
{
dungeon->things_in_hand[i] = newtng->index;
remove_thing_from_limbo(thing);
place_thing_in_limbo(newtng);
}
else
{
ERRORLOG("Picked up thing is not in player hand list");
}
}
kill_creature(thing, INVALID_THING, -1, CrDed_NoEffects|CrDed_NoUnconscious|CrDed_NotReallyDying);
return -1;
}

Expand Down Expand Up @@ -7635,6 +7553,108 @@ ThingModel get_random_creature_kind_with_model_flags(unsigned long model_flags)
return -1;
}

/* Returns a random creature kind, excluding spectators and diggers.
* Appropriate means evil and good creatures randomise within their respective classes. */
ThingModel get_random_appropriate_creature_kind(ThingModel original_model)
{
struct CreatureModelConfig *newconf;
struct CreatureModelConfig *oldconf = &game.conf.crtr_conf.model[original_model];
ThingModel random_model;
while (true)
{
random_model = GAME_RANDOM(game.conf.crtr_conf.model_count) + 1;
// Exclude out-of-bounds model number.
if (random_model >= game.conf.crtr_conf.model_count)
{
continue;
}
// Exclude same creature kind, spectators and diggers.
newconf = &game.conf.crtr_conf.model[random_model];
if ((random_model == original_model) || (flag_is_set(newconf->model_flags, CMF_IsSpectator)) || (flag_is_set(newconf->model_flags, CMF_IsSpecDigger)))
{
continue;
}
// Evil randomise into evil, good randomise into good.
if ((flag_is_set(newconf->model_flags, CMF_IsEvil)) && (flag_is_set(oldconf->model_flags, CMF_IsEvil)))
{
break;
}
if ((!flag_is_set(newconf->model_flags, CMF_IsEvil)) && (!flag_is_set(oldconf->model_flags, CMF_IsEvil)))
{
break;
}
}
return random_model;
}

TbBool grow_up_creature(struct Thing *thing, ThingModel grow_up_model, CrtrExpLevel grow_up_level)
{
if (grow_up_model == CREATURE_NOT_A_DIGGER)
{
grow_up_model = get_random_appropriate_creature_kind(thing->model);
}
if (!creature_count_below_map_limit(1))
{
WARNLOG("Could not create creature to transform %s to due to creature limit", thing_model_name(thing));
return false;
}
struct Thing *newtng = create_creature(&thing->mappos, grow_up_model, thing->owner);
if (thing_is_invalid(newtng))
{
ERRORLOG("Could not create creature to transform %s to", thing_model_name(thing));
return false;
}
// Randomise new level if 'grow_up_level' was set to 0 on the creature config.
if (grow_up_level == 0)
{
set_creature_level(newtng, GAME_RANDOM(CREATURE_MAX_LEVEL));
}
else
{
set_creature_level(newtng, grow_up_level - 1);
}
transfer_creature_data_and_gold(thing, newtng); // Transfer the blood type, creature name, kill count, joined age and carried gold to the new creature.
update_creature_health_to_max(newtng);
struct CreatureControl *cctrl = creature_control_get_from_thing(newtng);
cctrl->countdown = 50;
external_set_thing_state(newtng, CrSt_CreatureBeHappy);
struct PlayerInfo *player = get_player(thing->owner);
// Switch control if this creature is possessed.
if (is_thing_directly_controlled(thing))
{
leave_creature_as_controller(player, thing);
control_creature_as_controller(player, newtng);
}
if (is_thing_passenger_controlled(thing))
{
leave_creature_as_passenger(player, thing);
control_creature_as_passenger(player, newtng);
}
// If not directly nor passenger controlled, but still player is doing something with it.
if (thing->index == player->controlled_thing_idx)
{
set_selected_creature(player, newtng);
}
remove_creature_score_from_owner(thing); // kill_creature() doesn't call this.
// Handles picked up by player case.
if (thing_is_picked_up_by_player(thing, thing->owner))
{
struct Dungeon *dungeon = get_dungeon(thing->owner);
if (get_thing_in_hand_id(thing, thing->owner) >= 0)
{
dungeon->things_in_hand[get_thing_in_hand_id(thing, thing->owner)] = newtng->index;
remove_thing_from_limbo(thing);
place_thing_in_limbo(newtng);
}
else
{
ERRORLOG("Picked up thing is not in player hand list");
}
}
kill_creature(thing, INVALID_THING, -1, CrDed_NoEffects | CrDed_NoUnconscious | CrDed_NotReallyDying);
return true;
}

/******************************************************************************/
#ifdef __cplusplus
}
Expand Down
2 changes: 2 additions & 0 deletions src/thing_creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ PlayerNumber get_appropriate_player_for_creature(struct Thing *creatng);
/******************************************************************************/
void throw_out_gold(struct Thing* thing, long amount);
ThingModel get_random_creature_kind_with_model_flags(unsigned long model_flags);
ThingModel get_random_appropriate_creature_kind(ThingModel original_model);
TbBool grow_up_creature(struct Thing *thing, ThingModel grow_up_model, CrtrExpLevel grow_up_level);
/******************************************************************************/
#ifdef __cplusplus
}
Expand Down

0 comments on commit ad1fafb

Please sign in to comment.