-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for musical instruments (scale off perception) #11468
Changes from 3 commits
639ba06
dae5de1
8b99391
b03f735
cfd9e8d
53f136f
e22d679
ccc4cee
575c4c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -917,3 +917,109 @@ bool extended_firestarter_actor::can_use( const player* p, const item* it, bool | |
|
||
return true; | ||
} | ||
|
||
iuse_actor *musical_instrument_actor::clone() const | ||
{ | ||
return new musical_instrument_actor(*this); | ||
} | ||
|
||
void musical_instrument_actor::load( JsonObject &obj ) | ||
{ | ||
moves_cost = obj.get_int( "moves_cost", 25 ); | ||
volume = obj.get_int( "volume", 99 ); // Make it huge to alert the modder | ||
fun = obj.get_int( "fun", -100 ); // Likewise | ||
fun_bonus = obj.get_int( "fun_bonus", 0 ); | ||
description_frequency = obj.get_int( "description_frequency", 1 ); | ||
|
||
if( obj.has_array( "descriptions" ) ) { | ||
JsonArray jarr = obj.get_array( "descriptions" ); | ||
while( jarr.has_more() ) { | ||
const auto desc = jarr.next_string(); | ||
descriptions.push_back( desc ); | ||
} | ||
} else { | ||
descriptions.push_back( "You produce buggy chirping on your %s" ); | ||
} | ||
} | ||
|
||
long musical_instrument_actor::use( player *p, item *it, bool t, point ) const | ||
{ | ||
if( p == nullptr ) { | ||
// No haunted pianos here! | ||
it->active = false; | ||
return 0; | ||
} | ||
|
||
if( p->is_underwater() ) { | ||
p->add_msg_if_player( m_bad, _("You can't play music underwater") ); | ||
it->active = false; | ||
return 0; | ||
} | ||
|
||
if( !t ) { | ||
// TODO: Make the player stop playing music when paralyzed/choking | ||
if( it->active || p->has_effect("sleep") ) { | ||
p->add_msg_if_player( _("You stop playing your %s"), it->display_name().c_str() ); | ||
it->active = false; | ||
return 0; | ||
} | ||
} | ||
|
||
// Check for worn or wielded - no "floating"/bionic instruments for now | ||
// TODO: Distinguish instruments played with hands and with mouth, consider encumbrance | ||
const int inv_pos = p->get_item_position( it ); | ||
if( inv_pos > 0 || inv_pos == INT_MIN ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
p->add_msg_if_player( m_bad, _("You need to hold or wear %s to play it"), it->display_name().c_str() ); | ||
it->active = false; | ||
return 0; | ||
} | ||
|
||
// To prevent players from getting into a soft-lock and starving to death | ||
// How often does the player get to act | ||
const double actions_per_turn = 100.0 / p->get_speed(); | ||
// How much does it cost (per player action) to play this instrument continuously | ||
const double moves_per_action = moves_cost * actions_per_turn; | ||
if( p->get_speed() / 2.0 < moves_per_action ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can shorten this to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But won't it be harder to understand? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a very subjective thing, your view is as good as mine. However, if I wanted to know whether a certain character (given speed) can play that instrument, I'd have to do track the variables, which are not used anywhere else, so they could be removed. But they help understanding the code, so it's fine. Why actually this condition? It looks strange. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's there to make the player bail out of playing the instrument if half of the turn would be used up just on playing the instrument. Without such a safeguard (or with lower proportions), player could be locked up trying to play the instrument while dangerous things happen around. I think I'll change it to speed penalty, because it's safer, more obvious and doesn't penalize slow characters. |
||
p->add_msg_if_player( m_bad, _("You feel too weak to play your %s"), it->display_name().c_str() ); | ||
it->active = false; | ||
return 0; | ||
} | ||
|
||
// We can play the music now | ||
if( !it->active ) { | ||
p->add_msg_if_player( m_good, _("You start playing your %s"), it->display_name().c_str() ); | ||
it->active = true; | ||
} | ||
|
||
p->moves -= moves_cost; | ||
std::string desc = ""; | ||
const int morale_effect = fun + fun_bonus * p->per_cur; | ||
if( morale_effect >= 0 && int(calendar::turn) % description_frequency == 0 ) { | ||
const size_t desc_index = rng( 0, descriptions.size() - 1 ); | ||
desc = _(descriptions[ desc_index ].c_str()); | ||
} else if( morale_effect < 0 && int(calendar::turn) % 10 ) { | ||
// No musical skills = possible morale penalty | ||
desc = _("You produce an annoying sound"); | ||
sounds::ambient_sound( p->posx(), p->posy(), volume, desc ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That prints the sounds twice, it's printed below again. |
||
} | ||
|
||
sounds::ambient_sound( p->posx(), p->posy(), volume, desc ); | ||
|
||
if( !p->has_effect( "music" ) && !p->can_hear( p->pos(), volume ) ) { | ||
p->add_effect( "music", 1 ); | ||
const int sign = morale_effect > 0 ? 1 : -1; | ||
p->add_morale( MORALE_MUSIC, sign, morale_effect, 5, 2 ); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
bool musical_instrument_actor::can_use( const player *p, const item*, bool, const point& ) const | ||
{ | ||
// TODO (maybe): Mouth encumbrance? Smoke? Lack of arms? Hand encumbrance? | ||
if( p->is_underwater() ) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get this. If it's mandatory, why not omit the default value and let the json parser throw an error when it's missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't know parser drops errors on missing fields with no defaults.