Skip to content
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

[RDY] Adds weapon chemical launcher and new fungicidal gas type as ammo #12765

Merged
merged 14 commits into from
Jul 2, 2015
Merged
29 changes: 28 additions & 1 deletion data/json/items/ammo.json
Original file line number Diff line number Diff line change
Expand Up @@ -4389,7 +4389,8 @@
"recoil" : 0,
"count" : 1
},
{ "type" : "AMMO",
{
"type" : "AMMO",
"id" : "pointer_fake_ammo",
"price" : 0,
"name" : "point",
Expand All @@ -4410,6 +4411,32 @@
"dispersion" : 0,
"recoil" : 0,
"count" : 1
},
{
"type" : "AMMO",
"id" : "gas_fungicidal",
"category" : "chems",
"price" : 3500,
"name" : "sprayable fungicide",
"symbol" : "=",
"color" : "yellow",
"description" : "Fungicide enhanced with sulfur to create sprayable anti-fungal ammo for the chemical thrower. Best be used with some kind of mask or mouth protection.",
"material" : "null",
"volume" : 1,
"weight" : 1,
"phase" : "liquid",
"bashing" : 1,
"cutting" : 0,
"to_hit" : 0,
"ammo_type" : "gas_fungicidal",
"casing" : "NULL",
"damage" : 0,
"pierce" : 0,
"range" : 4,
"dispersion" : 0,
"recoil" : 0,
"count" : 100,
"effects" : [ "GAS_FUNGICIDAL", "STREAM_GAS_FUNGICIDAL", "NEVER_MISFIRES"]
}

]
6 changes: 6 additions & 0 deletions data/json/items/ammo_types.json
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,12 @@
"id" : "unfinished_char",
"name" : "semi-charred fuel",
"default" : "unfinished_charcoal"
},
{
"type" : "ammunition_type",
"id" : "gas_fungicidal",
"name" : "fungicidal gas",
"default" : "gas_fungicidal"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was having trouble with assigning a more general chemical_spray ammo-type. I wanted something like this:
{
"type" : "ammunition_type",
"id" : "chemical_spray",
"name" : "sprayable chemical",
"default" : "gas_fungicidal"
}

But it throws a debug-message, saying gas_fungicidal is not a valid ammo.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like you only changed it in ammo_types, but not in ammo.json: "gas_fungicidal" had the old "ammo_type" field.

"ammo" field refers to the ammo type id. So if you're changing ammo id to "chemical_spray", the fungicidal gas needs "ammo_type": "chemical_spray".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I did that ;) Still did not work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh forgot: the same in the thrower.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's it! Also, it makes much more sense, now that I think about it.

}

]
27 changes: 27 additions & 0 deletions data/json/items/ranged.json
Original file line number Diff line number Diff line change
Expand Up @@ -5428,5 +5428,32 @@
"built_in_mods": ["m203", "rifle_scope", "muzzle_brake"],
"default_mods": ["pistol_grip", "rail_laser_sight"],
"valid_mod_locations": [[ "accessories", 10 ],[ "barrel", 10 ],[ "bore", 10 ],[ "conversion", 10 ],[ "grip", 10 ],[ "magazine", 10 ],[ "mechanism", 10 ],[ "muzzle", 10 ],[ "rail", 10 ],[ "sights", 10 ],[ "stock", 10 ],[ "underbarrel", 10 ]]
},
{
"id": "chemical_thrower",
"type": "GUN",
"symbol": "(",
"color": "dark_gray",
"name": "chemical thrower",
"name_plural": "chemical throwers",
"description": "A bulky, self-made chemical sprayer with an internal conversion mechanism that allows all sorts of chemicals to be dispersed to your surroundings.",
"price": 15000,
"material": ["steel", "plastic"],
"flags": ["FIRE_100", "NEVER_JAMS"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fire 100 is quite a lot. With flamethrowers you can acquire the ammo easily by siphoning it from cars. Here you've got to craft every shot.

Fire 20 or 50 should be fine, unless you intend to make the gas very powerful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that one canister filling of 2000 units (so 20 uses) should be enough to eradicate one large patch of fungus. I can't really tell how the gas will spread by only looking at the code though, so I don't know when it would be considered overpowered. This thing shouldn't be the end-all anti-fungus tool.

"skill": "launcher",
"ammo": "gas_fungicidal",
"weight": 1150,
"volume": 25,
"bashing": 9,
"cutting": 0,
"to_hit": -1,
"ranged_damage": -5,
"dispersion": 300,
"sight_dispersion": 150,
"aim_speed" : 0,
"recoil": 0,
"durability": 6,
"clip_size": 2000,
"reload": 900
}
]
35 changes: 31 additions & 4 deletions data/json/recipes/recipe_ammo.json
Original file line number Diff line number Diff line change
Expand Up @@ -4435,8 +4435,35 @@
[ "solder_wire", 200 ]
]
]
},{
"type" : "recipe",
"result": "gas_fungicidal",
"category": "CC_AMMO",
"subcategory": "CSC_AMMO_OTHER",
"skill_used": "cooking",
"skills_required": [ "survival", 2 ],
"difficulty": 4,
"time": 2500,
"reversible": false,
"autolearn": false,
"book_learn": [[ "textbook_gaswarfare", 4 ] , ["textbook_chemistry", 4] , ["adv_chemistry", 4] , [ "recipe_labchem", 4]],
"qualities":[
{"id":"CHEM","level":1,"amount":1}
], "tools": [
[
[ "fire", -1 ],
[ "toolset", 3 ],
[ "hotplate", 3 ],
[ "char_smoker", 2 ]
]
],
"components": [
[
[ "fungicide", 100 ]
],
[
[ "chem_sulphur", 10 ]
]
]
}



]
]
48 changes: 48 additions & 0 deletions data/json/recipes/recipe_weapon.json
Original file line number Diff line number Diff line change
Expand Up @@ -6733,5 +6733,53 @@
["steel_chunk", 4],
["scrap", 12]]
]
},
{
"type" : "recipe",
"result": "chemical_thrower",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_RANGED",
"skill_used": "mechanics",
"skills_required": [ "launcher", 2 ],
"difficulty": 6,
"time": 12000,
"reversible": true,
"autolearn": true,
"qualities":[
{"id":"SAW_M_FINE","level":1,"amount":1},
{"id":"SCREW_FINE","level":1,"amount":1},
{"id":"HAMMER","level":2,"amount":1}
],
"tools":
[
[
["goggles_welding", -1]
],
[
["oxy_torch", 80],
["welder", 400],
["welder_crude", 550],
["toolset", 550]
]
],
"components": [
[
[ "pilot_light", 1 ]
],
[
[ "metal_tank_little", 1]
],
[
[ "pipe", 2 ]
],
[
[ "hose", 2 ]
],
[
[ "steel_lump", 1],
[ "steel_chunk", 4],
[ "scrap", 12]
]
]
}
]
9 changes: 7 additions & 2 deletions src/damage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,11 @@ void ammo_effects( const tripoint &p, const std::set<std::string> &effects )
g->m.add_field( pt, fd_tear_gas, 3, 0 );
}
}

if( effects.count( "GAS_FUNGICIDAL" ) > 0 ) {
for( auto &&pt : g->m.points_in_radius( p, 1, 0 ) ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be the line that allows defining the point of impact, rather than the point of origin?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know where to get the tripoint from, sorry 😭

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought you are just asking whether this is the solution to the problem of not having the point of impact.
Because it is: p is the last point the projectile reached and so the point of impact and the last possible point of impact at that.

This part is good.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, well that's an hour of code crawling well spent then.

The problem now is that the gas spawns in the tile the player is in, not the tile at which the launcher aims. Do I have to define a projectile somewhere?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably means the projectile loses all force before it reaches the target. In ranged.cpp, you've got Creature::projectile_attack - this deals with most of the projectile calculations.

Pretty sure just adding a "JET" flag to the ammo or adding an ammo effect "JET" to the launcher should be enough. "JET" flag has only one effect: negating the usual mechanic of projectile stopping when its damage reaches 0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yessssssssssssssssssssssssssss. You know your code 👯

Thank you for taking your time with me.

g->m.add_field( pt, fd_fungicidal_gas, 4, 0 );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you're adding a field with density 4. This will be ignored: density is capped at 3 at the moment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know. I thought this might let the gas linger longer so it simulates the effect of 'sinking in'. Should I revert it to 3?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map::add_field clips the density to 3, so having 4 here won't do anything.

Not sure what you mean by 'sinking in' here. That would probably be achieved better by changing the numbers in field processing, though. spread_gas has arguments like spread chance, outdoor dispersal speedup etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there was some kind of counter that reduces field density after a certain amount of time. Figured, if I set it higher the gas remains there longer, thereby simulating the gas 'hanging in the air' after it has been sprayed.
I'll look into spread_gas, that sounds exactly like what I need to modify.

}
}
if( effects.count( "SMOKE" ) > 0 ) {
for( auto &&pt : g->m.points_in_radius( p, 1, 0 ) ) {
g->m.add_field( pt, fd_smoke, 3, 0 );
Expand Down Expand Up @@ -243,7 +247,8 @@ int aoe_size( const std::set<std::string> &tags )
tags.count( "FRAG" ) ) {
return 2;
} else if( tags.count( "ACIDBOMB" ) ||
tags.count( "FLAME" ) ) {
tags.count( "FLAME" ) ||
tags.count( "GAS_FUNGICIDAL" ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aoe_size is currently only used for vehicles to avoid damaging themselves. It doesn't have other tags like "TEARGAS", so it probably shouldn't have "GAS_FUNGICIDAL" either, at least for now.

For toxic gases, some more specialized function will later exist (one that checks user's resistance).

return 1;
}

Expand Down
67 changes: 62 additions & 5 deletions src/field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,13 @@ void game::init_fields()
{"", "", ""}, '&', -1,
{c_white, c_yellow, c_red}, {true, true, true}, {false, false, false}, MINUTES(50),
{0,0,0}
},

{
"fd_fungicidal_gas",
{_("hazy cloud"),_("fungicidal gas"),_("thick fungicidal gas")}, '8', 8,
{c_white, c_ltgray, c_dkgray}, {true, true, false}, {false, true, true}, MINUTES(30),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also alter the time here. The MINUTES(30) is the average time it takes for the field to decay by 1 density.

{0,0,0}
}

};
Expand Down Expand Up @@ -753,7 +760,7 @@ bool map::process_fields_in_submap( submap *const current_submap,
// because the only trap we're checking for is brazier
const auto &ter = map_tile.get_ter_t();
const auto &frn = map_tile.get_furn_t();

const auto &trp = map_tile.get_trap();
// We've got ter/furn cached, so let's use that
const bool is_sealed = ter_furn_has_flag( ter, frn, TFLAG_SEALED ) &&
Expand Down Expand Up @@ -1004,7 +1011,7 @@ bool map::process_fields_in_submap( submap *const current_submap,
// The fire feeds on the ground itself until max density.
time_added += 4 - cur->getFieldDensity();
smoke += 2;
if( cur->getFieldDensity() > 1 &&
if( cur->getFieldDensity() > 1 &&
one_in( 200 - cur->getFieldDensity() * 50 ) ) {
destroy( p, true );
}
Expand All @@ -1013,7 +1020,7 @@ bool map::process_fields_in_submap( submap *const current_submap,
// The fire feeds on the ground itself until max density.
time_added += 5 - cur->getFieldDensity();
smoke += 2;
if( cur->getFieldDensity() > 1 &&
if( cur->getFieldDensity() > 1 &&
one_in( 200 - cur->getFieldDensity() * 50 ) ) {
ter_set( p, t_dirt );
furn_set( p, f_ash );
Expand All @@ -1030,7 +1037,7 @@ bool map::process_fields_in_submap( submap *const current_submap,
} else {
// Don't fuel raging fires or they'll burn forever
// as they can produce small fires above themselves
int new_density = std::max( cur->getFieldDensity(),
int new_density = std::max( cur->getFieldDensity(),
fire_there->getFieldDensity() );
// Allow smaller fires to combine
if( new_density < 3 &&
Expand Down Expand Up @@ -1162,7 +1169,7 @@ bool map::process_fields_in_submap( submap *const current_submap,
// Our iterator will start at end_i + 1 and increment from there and then wrap around.
// This guarantees it will check all neighbors, starting from a random one
const size_t end_i = (size_t)rng( 0, neighs.size() - 1 );
for( size_t i = ( end_i + 1 ) % neighs.size();
for( size_t i = ( end_i + 1 ) % neighs.size();
i != end_i; i = ( i + 1 ) % neighs.size() ) {
if( one_in( cur->getFieldDensity() * 2 ) ) {
// Skip some processing to save on CPU
Expand Down Expand Up @@ -1595,6 +1602,7 @@ bool map::process_fields_in_submap( submap *const current_submap,
curfield.findField( fd_relax_gas ) ||
curfield.findField( fd_nuke_gas ) ||
curfield.findField( fd_gas_vent ) ||
curfield.findField( fd_fungicidal_gas ) ||
curfield.findField( fd_fire_vent ) ||
curfield.findField( fd_flame_burst ) ||
curfield.findField( fd_electricity ) ||
Expand Down Expand Up @@ -1661,6 +1669,23 @@ bool map::process_fields_in_submap( submap *const current_submap,
make_rubble( p );
break;

case fd_fungicidal_gas:
{
dirty_transparency_cache = true;
//spread the chemical agent as fast as smoke would
spread_gas( cur, p, curtype, 80, 40 );
//check the terrain and replace it accordingly to simulate the fungus dieing off
const auto &ter = map_tile.get_ter_t();
const auto &frn = map_tile.get_furn_t();
if( ter.has_flag( "FUNGUS" ) ) {
ter_set( p, t_dirt );
}
if( frn.has_flag( "FUNGUS" ) ) {
furn_set( p, f_null );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to have separate check for furniture. Otherwise when a fungal terrain has a non-fungal furniture, it will be destroyed too.

}
}
break;

default:
//Suppress warnings
break;
Expand Down Expand Up @@ -2071,6 +2096,31 @@ void map::player_in_field( player &u )
}
break;

case fd_fungicidal_gas:
// Fungicidal gas makes you cough.
// Thick fungicidal gas has a chance to poison you.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you've crossed a fungal threshold like mycus or marloss? Shouldn't it be doing extra damage/poison to you?

{
bool inhaled = false;
if( cur->getFieldDensity() == 3 ) {
inhaled = u.add_env_effect("poison", bp_mouth, 5, 30);
} else if( cur->getFieldDensity() == 2 ) {
inhaled = u.add_env_effect("smoke", bp_mouth, 2, 7);
} else if( u.has_trait("THRESH_MYCUS") || u.has_trait("THRESH_MARLOSS" ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both of those else ifs are wrong:

  • Thick gas will not cause coughing, only poison. In many cases coughing can actually be more dangerous than poison
  • Mycus mutant will only get the mycus effect if the density == 1
  • In the mycus block: you don't need to compare density to any of 1, 2 or 3. It can never be lower than 1 or higher than 3
  • Density 1 should do something too. Maybe just a weak (5 turns?) poison effect?
  • Mycus mutants will take the damage even when in full hazmat

if( cur->getFieldDensity() == 3 ||
cur->getFieldDensity() == 2 ||
cur->getFieldDensity() == 1 ) {
inhaled = u.add_env_effect( "badpoison", bp_mouth, 5, 30 );
u.hurtall( rng(1,5), nullptr);
u.add_msg_if_player(m_bad, _("The %s burns your skin"), cur->name().c_str());
}
}
if( inhaled ) {
// player does not know how the npc feels, so no message.
u.add_msg_if_player(m_bad, _("You feel sick from inhaling the %s"), cur->name().c_str());
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't do anything with the inhaled variable.

break;

default:
//Suppress warnings
break;
Expand Down Expand Up @@ -2366,7 +2416,14 @@ void map::monster_in_field( monster &z )
z.moves -= rng( 10 * density, 30 * density );
dam += rng( 0, 10 * density );
}
break;

case fd_fungicidal_gas:
if( z.type->in_species("FUNGUS") ) {
const int density = cur->getFieldDensity();
z.moves -= rng( 10 * density, 30 * density );
dam += rng( 10, 15 * density );
}
break;

default:
Expand Down
1 change: 1 addition & 0 deletions src/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ enum field_id : int {
fd_hot_air2,
fd_hot_air3,
fd_hot_air4,
fd_fungicidal_gas,
num_fields
};

Expand Down
7 changes: 6 additions & 1 deletion src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2375,6 +2375,7 @@ void map::decay_fields_and_scent( const int amount )
break;
case fd_smoke:
case fd_toxic_gas:
case fd_fungicidal_gas:
case fd_tear_gas:
case fd_nuke_gas:
case fd_cigsmoke:
Expand Down Expand Up @@ -3011,7 +3012,7 @@ std::pair<bool, bool> map::bash_ter_furn( const tripoint &p, const int str,
if( !sound.empty() && !silent ) {
sounds::sound( p, sound_volume, sound, false, "bash", sound );
}

return std::pair<bool, bool>( smashed_something, success );
}

Expand Down Expand Up @@ -3382,6 +3383,10 @@ void map::shoot( const tripoint &p, int &dam,
add_field(p, fd_fire, rng(1, 2), 0 );
}

if (ammo_effects.count("STREAM_GAS_FUNGICIDAL") && !one_in(3)) {
add_field(p, fd_fungicidal_gas, rng(1, 2), 0 );
}

if (ammo_effects.count("STREAM_BIG") && !one_in(4)) {
add_field(p, fd_fire, 2, 0 );
}
Expand Down