Skip to content

Commit

Permalink
Prepare npc, spell, character, and item for new ai (#47207)
Browse files Browse the repository at this point in the history
  • Loading branch information
KorGgenT authored and ZhilkinSerg committed Mar 18, 2021
1 parent 8e78741 commit e95e424
Show file tree
Hide file tree
Showing 15 changed files with 338 additions and 123 deletions.
2 changes: 1 addition & 1 deletion src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2675,7 +2675,7 @@ int Character::get_mod_stat_from_bionic( const character_stat &Stat ) const
return ret;
}

int Character::get_standard_stamina_cost( item *thrown_item )
int Character::get_standard_stamina_cost( const item *thrown_item ) const
{
// Previously calculated as 2_gram * std::max( 1, str_cur )
// using 16_gram normalizes it to 8 str. Same effort expenditure
Expand Down
7 changes: 6 additions & 1 deletion src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ class Character : public Creature, public visitable

void mod_stat( const std::string &stat, float modifier ) override;

int get_standard_stamina_cost( item *thrown_item = nullptr );
int get_standard_stamina_cost( const item *thrown_item = nullptr ) const;

/**Get bonus to max_hp from excess stored fat*/
int get_fat_to_hp() const;
Expand Down Expand Up @@ -1648,6 +1648,10 @@ class Character : public Creature, public visitable
*/
int item_reload_cost( const item &it, const item &ammo, int qty ) const;

projectile thrown_item_projectile( const item &thrown ) const;
int thrown_item_adjusted_damage( const item &thrown ) const;
// calculates the total damage possible from a thrown item, without resistances and such.
int thrown_item_total_damage_raw( const item &thrown ) const;
/** Maximum thrown range with a given item, taking all active effects into account. */
int throw_range( const item & ) const;
/** Dispersion of a thrown item, against a given target, taking into account whether or not the throw was blind. */
Expand Down Expand Up @@ -1860,6 +1864,7 @@ class Character : public Creature, public visitable
// gets all the spells known by this character that have this spell class
// spells returned are a copy, do not try to edit them from here, instead use known_magic::get_spell
std::vector<spell> spells_known_of_class( const trait_id &spell_class ) const;
bool cast_spell( spell &sp, bool fake_spell, cata::optional<tripoint> target );

void make_bleed( const effect_source &source, const bodypart_id &bp, time_duration duration,
int intensity = 1, bool permanent = false, bool force = false, bool defferred = false );
Expand Down
7 changes: 7 additions & 0 deletions src/creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class anatomy;
class avatar;
class field;
class field_entry;
class npc;
class player;
class time_duration;
struct point;
Expand Down Expand Up @@ -263,6 +264,12 @@ class Creature : public location, public viewer
virtual const avatar *as_avatar() const {
return nullptr;
}
virtual const npc *as_npc() {
return nullptr;
}
virtual const npc *as_npc() const {
return nullptr;
}
virtual monster *as_monster() {
return nullptr;
}
Expand Down
20 changes: 10 additions & 10 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1484,7 +1484,7 @@ static const double hits_by_accuracy[41] = {
9993, 9997, 9998, 9999, 10000 // 16 to 20
};

double item::effective_dps( const Character &guy, monster &mon ) const
double item::effective_dps( const Character &guy, Creature &mon ) const
{
const float mon_dodge = mon.get_dodge();
float base_hit = guy.get_dex() / 4.0f + guy.get_hit_weapon( *this );
Expand Down Expand Up @@ -1519,19 +1519,19 @@ double item::effective_dps( const Character &guy, monster &mon ) const
// sum average damage past armor and return the number of moves required to achieve
// that damage
const auto calc_effective_damage = [ &, moves_per_attack]( const double num_strikes,
const bool crit, const Character & guy, monster & mon ) {
monster temp_mon = mon;
const bool crit, const Character & guy, Creature & mon ) {
Creature *temp_mon = &mon;
double subtotal_damage = 0;
damage_instance base_damage;
guy.roll_all_damage( crit, base_damage, true, *this );
damage_instance dealt_damage = base_damage;
temp_mon.absorb_hit( bodypart_id( "torso" ), dealt_damage );
temp_mon->absorb_hit( bodypart_id( "torso" ), dealt_damage );
dealt_damage_instance dealt_dams;
for( const damage_unit &dmg_unit : dealt_damage.damage_units ) {
int cur_damage = 0;
int total_pain = 0;
temp_mon.deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ),
cur_damage, total_pain );
temp_mon->deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ),
cur_damage, total_pain );
if( cur_damage > 0 ) {
dealt_dams.dealt_dams[ static_cast<int>( dmg_unit.type )] += cur_damage;
}
Expand All @@ -1541,20 +1541,20 @@ double item::effective_dps( const Character &guy, monster &mon ) const
double subtotal_moves = moves_per_attack * num_strikes;

if( has_technique( RAPID ) ) {
monster temp_rs_mon = mon;
Creature *temp_rs_mon = &mon;
damage_instance rs_base_damage;
guy.roll_all_damage( crit, rs_base_damage, true, *this );
damage_instance dealt_rs_damage = rs_base_damage;
for( damage_unit &dmg_unit : dealt_rs_damage.damage_units ) {
dmg_unit.damage_multiplier *= 0.66;
}
temp_rs_mon.absorb_hit( bodypart_id( "torso" ), dealt_rs_damage );
temp_rs_mon->absorb_hit( bodypart_id( "torso" ), dealt_rs_damage );
dealt_damage_instance rs_dealt_dams;
for( const damage_unit &dmg_unit : dealt_rs_damage.damage_units ) {
int cur_damage = 0;
int total_pain = 0;
temp_rs_mon.deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ),
cur_damage, total_pain );
temp_rs_mon->deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ),
cur_damage, total_pain );
if( cur_damage > 0 ) {
rs_dealt_dams.dealt_dams[ static_cast<int>( dmg_unit.type ) ] += cur_damage;
}
Expand Down
3 changes: 2 additions & 1 deletion src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "visitable.h"

class Character;
class Creature;
class JsonIn;
class JsonObject;
class JsonOut;
Expand Down Expand Up @@ -619,7 +620,7 @@ class item : public visitable
* Calculate the item's effective damage per second past armor when wielded by a
* character against a monster.
*/
double effective_dps( const Character &guy, monster &mon ) const;
double effective_dps( const Character &guy, Creature &mon ) const;
/**
* calculate effective dps against a stock set of monsters. by default, assume g->u
* is wielding
Expand Down
92 changes: 88 additions & 4 deletions src/magic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <tuple>
#include <utility>

#include "avatar.h"
#include "calendar.h"
#include "cata_utility.h"
#include "catacharset.h"
Expand All @@ -33,14 +34,17 @@
#include "make_static.h"
#include "magic_enchantment.h"
#include "map.h"
#include "map_iterator.h"
#include "messages.h"
#include "mongroup.h"
#include "monster.h"
#include "mtype.h"
#include "mutation.h"
#include "npc.h"
#include "output.h"
#include "pimpl.h"
#include "point.h"
#include "projectile.h"
#include "requirements.h"
#include "rng.h"
#include "sounds.h"
Expand Down Expand Up @@ -565,6 +569,18 @@ int spell::min_leveled_damage() const
return type->min_damage + std::round( get_level() * type->damage_increment );
}

float spell::dps( const Character &caster, const Creature & ) const
{
if( type->effect_name != "attack" ) {
return 0.0f;
}
const float time_modifier = 100.0f / casting_time( caster );
const float failure_modifier = 1.0f - spell_fail( caster );
const float raw_dps = damage() + damage_dot() * duration_turns() / 1_turns;
// TODO: calculate true dps with armor and resistances and any caster bonuses
return raw_dps * time_modifier * failure_modifier;
}

int spell::damage() const
{
const int leveled_damage = min_leveled_damage();
Expand Down Expand Up @@ -679,6 +695,45 @@ int spell::range() const
}
}

std::vector<tripoint> spell::targetable_locations( const Character &source ) const
{

const tripoint char_pos = source.pos();
const bool select_ground = is_valid_target( spell_target::ground );
const bool ignore_walls = has_flag( spell_flag::NO_PROJECTILE );
map &here = get_map();

// TODO: put this in a namespace for reuse
const auto has_obstruction = [&]( const tripoint & at ) {
for( const tripoint &line_point : line_to( char_pos, at ) ) {
if( here.impassable( line_point ) ) {
return true;
}
}
return false;
};

std::vector<tripoint> selectable_targets;
for( const tripoint &query : here.points_in_radius( char_pos, range() ) ) {
if( !ignore_walls && has_obstruction( query ) ) {
// it's blocked somewhere!
continue;
}

if( !select_ground ) {
if( !source.sees( query ) ) {
// can't target a critter you can't see
continue;
}
}

if( is_valid_target( source, query ) ) {
selectable_targets.push_back( query );
}
}
return selectable_targets;
}

int spell::min_leveled_duration() const
{
return type->min_duration + std::round( get_level() * type->duration_increment );
Expand Down Expand Up @@ -792,14 +847,17 @@ bool spell::is_spell_class( const trait_id &mid ) const
return mid == type->spell_class;
}

bool spell::can_cast( Character &guy ) const
bool spell::can_cast( const Character &guy ) const
{
if( guy.has_trait_flag( STATIC( json_character_flag( "NO_SPELLCASTING" ) ) ) ) {
return false;
}

// only required because crafting_inventory always rebuilds the cache. maybe a const version doesn't write to cache.
Character &guy_inv = const_cast<Character &>( guy );

if( !type->spell_components.is_empty() &&
!type->spell_components->can_make_with_inventory( guy.crafting_inventory( guy.pos(), 0 ),
!type->spell_components->can_make_with_inventory( guy_inv.crafting_inventory( guy.pos(), 0 ),
return_true<item> ) ) {
return false;
}
Expand Down Expand Up @@ -1076,13 +1134,22 @@ void spell::create_field( const tripoint &at ) const
}
}

void spell::make_sound( const tripoint &target ) const
int spell::sound_volume() const
{
int loudness = 0;
if( !has_flag( spell_flag::SILENT ) ) {
int loudness = std::abs( damage() ) / 3;
loudness = std::abs( damage() ) / 3;
if( has_flag( spell_flag::LOUD ) ) {
loudness += 1 + damage() / 3;
}
}
return loudness;
}

void spell::make_sound( const tripoint &target ) const
{
const int loudness = sound_volume();
if( loudness > 0 ) {
make_sound( target, loudness );
}
}
Expand Down Expand Up @@ -1307,6 +1374,23 @@ dealt_damage_instance spell::get_dealt_damage_instance() const
return dmg;
}

dealt_projectile_attack spell::get_projectile_attack( const tripoint &target,
Creature &hit_critter ) const
{
projectile bolt;
bolt.speed = 10000;
bolt.impact = get_damage_instance();
bolt.proj_effects.emplace( "magic" );

dealt_projectile_attack atk;
atk.end_point = target;
atk.hit_critter = &hit_critter;
atk.proj = bolt;
atk.missed_by = 0.0;

return atk;
}

std::string spell::effect_data() const
{
return type->effect_str;
Expand Down
14 changes: 13 additions & 1 deletion src/magic.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class JsonOut;
class nc_color;
class spell;
class time_duration;
struct dealt_projectile_attack;
struct requirement_data;

namespace spell_effect
Expand Down Expand Up @@ -441,14 +442,24 @@ class spell
int damage_dot() const;
damage_over_time_data damage_over_time( const std::vector<bodypart_str_id> &bps ) const;
dealt_damage_instance get_dealt_damage_instance() const;
dealt_projectile_attack get_projectile_attack( const tripoint &target,
Creature &hit_critter ) const;
damage_instance get_damage_instance() const;
// calculate damage per second against a target
float dps( const Character &caster, const Creature &target ) const;
// how big is the spell's radius
int aoe() const;
std::set<tripoint> effect_area( const spell_effect::override_parameters &params,
const tripoint &source, const tripoint &target ) const;
std::set<tripoint> effect_area( const tripoint &source, const tripoint &target ) const;
// distance spell can be cast
int range() const;
/**
* all of the tripoints the spell can be cast at.
* if the spell can't be cast through walls, does not return anything behind walls
* if the spell can't target the ground, can't target unseen locations, etc.
*/
std::vector<tripoint> targetable_locations( const Character &source ) const;
// how much energy does the spell cost
int energy_cost( const Character &guy ) const;
// how long does this spell's effect last
Expand All @@ -464,7 +475,7 @@ class spell
const requirement_data &components() const;
bool has_components() const;
// can the Character cast this spell?
bool can_cast( Character &guy ) const;
bool can_cast( const Character &guy ) const;
// can the Character learn this spell?
bool can_learn( const Character &guy ) const;
// is this spell valid
Expand Down Expand Up @@ -525,6 +536,7 @@ class spell
// tries to create a field at the location specified
void create_field( const tripoint &at ) const;

int sound_volume() const;
// makes a spell sound at the location
void make_sound( const tripoint &target ) const;
void make_sound( const tripoint &target, int loudness ) const;
Expand Down
11 changes: 1 addition & 10 deletions src/magic_spell_effect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,16 +471,7 @@ static void damage_targets( const spell &sp, Creature &caster,
continue;
}

projectile bolt;
bolt.speed = 10000;
bolt.impact = sp.get_damage_instance();
bolt.proj_effects.emplace( "magic" );

dealt_projectile_attack atk;
atk.end_point = target;
atk.hit_critter = cr;
atk.proj = bolt;
atk.missed_by = 0.0;
dealt_projectile_attack atk = sp.get_projectile_attack( target, *cr );
if( !sp.effect_data().empty() ) {
add_effect_to_target( target, sp );
}
Expand Down
Loading

0 comments on commit e95e424

Please sign in to comment.