Skip to content

Commit

Permalink
feat: Lua bindings for mutation introspection, creature temperature (#…
Browse files Browse the repository at this point in the history
…5797)

* Bindings to allow setting/reading character body temps.

* Fixed overloading for some Lua bindings

* Added method to get every bodypart's temperature at once

* Added bindings for (read-only) mutation_branch examination.

* Added more MutationBranch Lua bindings.

* Removed an extraneous comment.

* Minor formatting adjustments.

* MORE MINOR FORMATTING ADJUSTMENTS I HAVE BEEN AWAKE FOR TOO LONG

* style(autofix.ci): automated formatting

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
karxi and autofix-ci[bot] authored Dec 10, 2024
1 parent 47757d2 commit 062461f
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/catalua_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,7 @@ void cata::reg_all_bindings( sol::state &lua )
reg_colors( lua );
reg_enums( lua );
reg_game_ids( lua );
mod_mutation_branch( lua );
reg_coords_library( lua );
reg_constants( lua );
reg_hooks_examples( lua );
Expand Down
1 change: 1 addition & 0 deletions src/catalua_bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ void reg_item( sol::state &lua );
void reg_locale_api( sol::state &lua );
void reg_map( sol::state &lua );
void reg_monster( sol::state &lua );
void mod_mutation_branch( sol::state &lua );
void reg_npc( sol::state &lua );
void reg_player( sol::state &lua );
void reg_point_tripoint( sol::state &lua );
Expand Down
24 changes: 22 additions & 2 deletions src/catalua_bindings_creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,18 @@ void cata::detail::reg_character( sol::state &lua )

SET_FX_T( has_watch, bool() const );

// These are named with 'BTU' (body temperature units) because other
// body temperature measurements might/can/should be added later.
DOC( "Gets the current temperature of a specific body part (in Body Temperature Units)." );
SET_FX_N_T( get_part_temp_cur, "get_part_temp_btu", int( const bodypart_id & id ) const );
DOC( "Sets a specific body part to a given temperature (in Body Temperature Units)." );
SET_FX_N_T( set_part_temp_cur, "set_part_temp_btu", void( const bodypart_id & id, int temp ) );
DOC( "Gets all bodyparts and their associated temperatures (in Body Temperature Units)." );
// May want to remove the 'resolve' call, but it clarifies the type...
luna::set_fx( ut, "get_temp_btu", sol::resolve< std::map<bodypart_id, int>() >( &UT_CLASS::get_temp_cur ) );
DOC( "Sets ALL body parts on a creature to the given temperature (in Body Temperature Units)." );
SET_FX_N_T( set_temp_cur, "set_temp_btu", void( int temp ) );

SET_FX_T( blood_loss, int( const bodypart_id & bp ) const );

SET_FX_N_T( encumb, "get_part_encumbrance", int( const bodypart_str_id & bp ) const );
Expand Down Expand Up @@ -526,6 +538,12 @@ void cata::detail::reg_character( sol::state &lua )

SET_FX_T( mutate_towards, bool( const trait_id & ) );

luna::set_fx( ut, "mutate_towards", sol::overload(
sol::resolve<bool( std::vector<trait_id>, int )>( &UT_CLASS::mutate_towards ),
sol::resolve<bool( const trait_id & )>( &UT_CLASS::mutate_towards )
) );


SET_FX_T( remove_mutation, void( const trait_id &, bool ) );

SET_FX_T( has_child_flag, bool( const trait_id & flag ) const );
Expand Down Expand Up @@ -714,8 +732,10 @@ void cata::detail::reg_character( sol::state &lua )

SET_FX_T( rooted, void() );

SET_FX_T( fall_asleep, void() );
SET_FX_T( fall_asleep, void( const time_duration & duration ) );
luna::set_fx( ut, "fall_asleep", sol::overload(
sol::resolve<void()>( &UT_CLASS::fall_asleep ),
sol::resolve<void( const time_duration &duration )>( &UT_CLASS::fall_asleep )
) );

SET_FX_T( get_hostile_creatures, std::vector<Creature *>( int ) const );

Expand Down
177 changes: 177 additions & 0 deletions src/catalua_bindings_mutation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#ifdef LUA
#include "catalua_bindings.h"

#include "catalua.h"
// Thx Almantuxas
#include "catalua_bindings_utils.h"
#include "catalua_impl.h"
#include "catalua_log.h"
#include "catalua_luna.h"
#include "catalua_luna_doc.h"

#include "mutation.h"

void cata::detail::mod_mutation_branch( sol::state &lua )
{
#define UT_CLASS mutation_branch
{
/* NOTE: These changes are applied to the "MutationBranchRaw" Lua obj.
* Because mutation_branch was bound as an ID, the actual object is
* shoved into a 'Raw' binding.
* The following code makes that useful, while also stopping the
* related object from being messed with.
*/
sol::usertype<UT_CLASS> ut =
luna::new_usertype<UT_CLASS>(
lua,
luna::no_bases,
luna::no_constructor
);

// Lets us grab the MutationBranchId from a MutationBranchRaw object.
SET_MEMB_RO( id );

/* === General Mutation Statistics === */
DOC( "Whether this mutation is available through generic mutagen." );
SET_MEMB_RO( valid );
DOC( "Whether this mutation is possible to remove through Purifier. False for 'special' mutations." );
SET_MEMB_RO( purifiable );
DOC( "Whether this is a Threshold mutation, and thus especially difficult to mutate. One per character." );
SET_MEMB_RO( threshold );
DOC( "Whether this trait is ONLY gained through professional training/experience (and/or quests)." );
SET_MEMB_RO( profession );
DOC( "Whether or not this mutation is limited to debug use." );
SET_MEMB_RO( debug );
DOC( "Whether or not this mutation shows up in the status (`@`) menu." );
SET_MEMB_RO( player_display );
DOC( "Whether this mutation has positive /and/ negative effects." );
SET_MEMB_RO( mixed_effect );
DOC( "Whether this trait can normally be taken during character generation." );
SET_MEMB_N_RO( startingtrait, "starting_trait" );
DOC( "Whether this mutation can be activated at will." );
SET_MEMB_RO( activated );
DOC( "Whether a mutation activates when granted." );
SET_MEMB_RO( starts_active );
DOC( "Mutation allows soft gear to be worn over otherwise-restricted parts." );
SET_MEMB_RO( allow_soft_gear );
DOC( "Mutation causes fatigue when used." );
SET_MEMB_RO( fatigue );
DOC( "Mutation deducts calories when used." );
SET_MEMB_RO( hunger );
DOC( "Mutation dehydrates when used." );
SET_MEMB_RO( thirst );
DOC( "Point cost in character creation(?)." );
SET_MEMB_RO( points );
DOC( "How visible the mutation is to others." );
SET_MEMB_RO( visibility );
DOC( "How physically unappealing the mutation is. Can be negative." );
SET_MEMB_RO( ugliness );

SET_MEMB_RO( cost );
DOC( "Costs are incurred every 'cooldown' turns." );
SET_MEMB_RO( cooldown );

/* === Modifiers === */
SET_MEMB_N_RO( bodytemp_min, "bodytemp_min_btu" );
SET_MEMB_N_RO( bodytemp_max, "bodytemp_max_btu" );
SET_MEMB_N_RO( bodytemp_sleep, "bodytemp_sleep_btu" );

DOC( "Pain recovery per turn from mutation." );
SET_MEMB_RO( pain_recovery );
DOC( "Healing per turn from mutation." );
SET_MEMB_RO( healing_awake );
DOC( "Healing per turn from mutation, while asleep." );
SET_MEMB_RO( healing_resting );
DOC( "Multiplier applied to broken limb regeneration. Normally 0.25; clamped to 0.25..1.0." );
SET_MEMB_RO( mending_modifier );
DOC( "Bonus HP multiplier. 1.0 doubles HP; -0.5 halves it." );
SET_MEMB_RO( hp_modifier );
DOC( "Secondary HP multiplier; stacks with the other one. 1.0 doubles HP; -0.5 halves it." );
SET_MEMB_RO( hp_modifier_secondary );
DOC( "Flat adjustment to HP." );
SET_MEMB_RO( hp_adjustment );
DOC( "Adjustment to Strength that doesn't affect HP." );
SET_MEMB_RO( str_modifier );

SET_MEMB_RO( dodge_modifier );
SET_MEMB_RO( speed_modifier );
SET_MEMB_RO( movecost_modifier );
SET_MEMB_RO( movecost_flatground_modifier );
SET_MEMB_RO( movecost_obstacle_modifier );
SET_MEMB_RO( attackcost_modifier );
SET_MEMB_RO( falling_damage_multiplier );
SET_MEMB_RO( max_stamina_modifier );
SET_MEMB_RO( weight_capacity_modifier );
SET_MEMB_RO( hearing_modifier );
SET_MEMB_RO( movecost_swim_modifier );
SET_MEMB_RO( noise_modifier );
SET_MEMB_RO( scent_modifier );
SET_MEMB_RO( bleed_resist );

DOC( "How quickly health (not HP) trends toward healthy_mod." );
SET_MEMB_RO( healthy_rate );
SET_MEMB_RO( stealth_modifier );
SET_MEMB_RO( night_vision_range );
SET_MEMB_RO( temperature_speed_modifier );
SET_MEMB_RO( metabolism_modifier );
SET_MEMB_RO( thirst_modifier );
SET_MEMB_RO( fatigue_modifier );
SET_MEMB_RO( fatigue_regen_modifier );
SET_MEMB_RO( stamina_regen_modifier );

SET_MEMB_RO( overmap_sight );
SET_MEMB_RO( overmap_multiplier );
SET_MEMB_RO( reading_speed_multiplier );
SET_MEMB_RO( skill_rust_multiplier );

SET_FX_T( name, std::string() const );
SET_FX_T( desc, std::string() const );

DOC( "Returns a (long) list of every mutation in the game." );
SET_FX_T( get_all, const std::vector<mutation_branch> &() );

// The string conversion function references this object's str_id.
luna::set_fx( ut, sol::meta_function::to_string,
[]( const UT_CLASS & id ) -> std::string {
return string_format( "%s[%s]", luna::detail::luna_traits<UT_CLASS>::name, id.id.c_str() );
} );

// Copy the return values so they can't be modified in-place.
DOC( "Lists the primary mutation(s) needed to gain this mutation." );
luna::set_fx( ut, "prerequisites", []( const UT_CLASS & mut ) -> std::vector<trait_id> {
std::vector<trait_id> rv = mut.prereqs; return rv;
} );
DOC( "Lists the secondary mutation(s) needed to gain this mutation." );
luna::set_fx( ut, "other_prerequisites", []( const UT_CLASS & mut ) -> std::vector<trait_id> {
std::vector<trait_id> rv = mut.prereqs2; return rv;
} );
DOC( "Lists the threshold mutation(s) required to gain this mutation." );
luna::set_fx( ut, "thresh_requirements", []( const UT_CLASS & mut ) -> std::vector<trait_id> {
std::vector<trait_id> rv = mut.threshreq; return rv;
} );
DOC( "Lists the type(s) of this mutation. Mutations of a given type are mutually exclusive." );
luna::set_fx( ut, "mutation_types", []( const UT_CLASS & mut ) -> std::set<std::string> {
std::set<std::string> rv = mut.types; return rv;
} );
DOC( "Lists conflicting mutations." );
luna::set_fx( ut, "conflicts_with", []( const UT_CLASS & mut ) -> std::vector<trait_id> {
std::vector<trait_id> rv = mut.cancels; return rv;
} );
DOC( "Lists mutations that replace (e.g. evolve from) this one." );
luna::set_fx( ut, "replaced_by", []( const UT_CLASS & mut ) -> std::vector<trait_id> {
std::vector<trait_id> rv = mut.replacements; return rv;
} );
luna::set_fx( ut, "addition_mutations", []( const UT_CLASS & mut ) -> std::vector<trait_id> {
std::vector<trait_id> rv = mut.additions; return rv;
} );
DOC( "Lists the categories this mutation belongs to." );
luna::set_fx( ut, "categories", []( const UT_CLASS & mut ) -> std::vector<mutation_category_id> {
std::vector<mutation_category_id> rv = mut.category; return rv;
} );
/* Would bind .flags to .trait_flags(), but json_trait_flag does not
* seem to have definitions for comparison to itself.
*/
}
#undef UT_CLASS // #define UT_CLASS mutation_branch
}
#endif // #ifdef LUA
4 changes: 4 additions & 0 deletions src/catalua_bindings_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ void reg_serde_functions( sol::usertype<T> &ut )
#define SET_MEMB(prop_name) luna::set( ut, #prop_name, &UT_CLASS::prop_name )
// SET MEMBer with Name
//#define SET_MEMB_N(prop_name, lua_name_str) luna::set( ut, lua_name_str, &UT_CLASS::prop_name )
// SET MEMBer, Read-Only
#define SET_MEMB_RO(prop_name) luna::set( ut, #prop_name, sol::readonly( &UT_CLASS::prop_name ) )
// SET MEMBer with Name, Read-Only
#define SET_MEMB_N_RO(prop_name, lua_name_str) luna::set( ut, lua_name_str, sol::readonly( &UT_CLASS::prop_name ) )
// SET FX (function)
#define SET_FX(func_name) luna::set_fx ( ut, #func_name, &UT_CLASS::func_name)
// SET FX (function) with Type
Expand Down
9 changes: 9 additions & 0 deletions src/catalua_luna.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,15 @@ void doc_member( sol::table &dt, sol::types<Value Class::*> && )
dt[KEY_MEMBER_VARIABLE_TYPE] = doc_value( sol::types<Value>() );
}

// Olanti! Curse thee for what I must do!
template<typename Class, typename Value>
void doc_member( sol::table &dt, sol::types<sol::readonly_wrapper<Value Class::*>> && )
{
dt[KEY_MEMBER_TYPE] = MEMBER_IS_VAR;
add_comment( dt, KEY_MEMBER_COMMENT );
dt[KEY_MEMBER_VARIABLE_TYPE] = doc_value( sol::types<Value>() );
}

template<typename Class, bool add_self_arg, typename RetVal, typename ...Args>
void doc_member_fx_impl2( sol::table &dt, sol::types<RetVal> &&, sol::types<Args...> && )
{
Expand Down
1 change: 1 addition & 0 deletions src/catalua_luna_doc.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct damage_instance;
struct damage_unit;
struct dealt_damage_instance;
struct field_type;
struct mutation_branch;
struct npc_opinion;
struct npc_personality;
struct point;
Expand Down
30 changes: 30 additions & 0 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6083,6 +6083,36 @@ void Character::update_bodytemp( const map &m, const weather_manager &weather )
}
}

int Character::get_part_temp_cur( const bodypart_id &id ) const
{
return get_part( id ).get_temp_cur();
}

void Character::set_part_temp_cur( const bodypart_id &id, int temp )
{
get_part( id ).set_temp_cur( temp );
}

std::map<bodypart_id, int> Character::get_temp_cur()
{
std::map<bodypart_id, int> temps;

for( auto &pr : get_body() ) {
bodypart &bp = pr.second;
temps[ bp.get_id() ] = bp.get_temp_cur();
}
return temps;
}

void Character::set_temp_cur( int temp )
{
for( auto &pr : get_body() ) {
bodypart &bp = pr.second;
bp.set_temp_cur( temp );
}
}


int Character::blood_loss( const bodypart_id &bp ) const
{
int hp_cur_sum = get_part_hp_cur( bp );
Expand Down
7 changes: 7 additions & 0 deletions src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,13 @@ class Character : public Creature, public location_visitable<Character>
/** Maintains body temperature */
void update_bodytemp( const map &m, const weather_manager &weather );

/** Getters/setters for body part temperature.
* This could go under Creature, but Character is the class with update_bodytemp. */
int get_part_temp_cur( const bodypart_id &id ) const;
void set_part_temp_cur( const bodypart_id &id, int temp );
std::map<bodypart_id, int> get_temp_cur();
void set_temp_cur( int temp );

/** Define blood loss (in percents) */
int blood_loss( const bodypart_id &bp ) const;

Expand Down

0 comments on commit 062461f

Please sign in to comment.