Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| #include "tutorial.h" | |
| #include "coordinate_conversions.h" | |
| #include "gamemode.h" | |
| #include "game.h" | |
| #include "map.h" | |
| #include "output.h" | |
| #include "action.h" | |
| #include "overmapbuffer.h" | |
| #include "translations.h" | |
| #include "profession.h" | |
| #include "overmap.h" | |
| #include "trap.h" | |
| #include "player.h" | |
| #include "scent_map.h" | |
| const mtype_id mon_zombie( "mon_zombie" ); | |
| std::vector<std::string> tut_text; | |
| bool tutorial_game::init() | |
| { | |
| // TODO: clean up old tutorial | |
| calendar::turn = HOURS( 12 ); // Start at noon | |
| for( auto &elem : tutorials_seen ) { | |
| elem = false; | |
| } | |
| g->scent.reset(); | |
| g->temperature = 65; | |
| // We use a Z-factor of 10 so that we don't plop down tutorial rooms in the | |
| // middle of the "real" game world | |
| g->u.normalize(); | |
| g->u.str_cur = g->u.str_max; | |
| g->u.per_cur = g->u.per_max; | |
| g->u.int_cur = g->u.int_max; | |
| g->u.dex_cur = g->u.dex_max; | |
| for( int i = 0; i < num_hp_parts; i++ ) { | |
| g->u.hp_cur[i] = g->u.hp_max[i]; | |
| } | |
| const oter_id rock( "rock" ); | |
| //~ default name for the tutorial | |
| g->u.name = _( "John Smith" ); | |
| g->u.prof = profession::generic(); | |
| int lx = 50, ly = 50; // overmap terrain coordinates | |
| auto &starting_om = overmap_buffer.get( 0, 0 ); | |
| for( int i = 0; i < OMAPX; i++ ) { | |
| for( int j = 0; j < OMAPY; j++ ) { | |
| starting_om.ter( i, j, -1 ) = rock; | |
| // Start with the overmap revealed | |
| starting_om.seen( i, j, 0 ) = true; | |
| } | |
| } | |
| starting_om.ter( lx, ly, 0 ) = oter_id( "tutorial" ); | |
| starting_om.ter( lx, ly, -1 ) = oter_id( "tutorial" ); | |
| starting_om.clear_mon_groups(); | |
| g->u.toggle_trait( "QUICK" ); | |
| item lighter( "lighter", 0 ); | |
| lighter.invlet = 'e'; | |
| g->u.inv.add_item( lighter ); | |
| g->u.set_skill_level( skill_id( "gun" ), 5 ); | |
| g->u.set_skill_level( skill_id( "melee" ), 5 ); | |
| g->load_map( omt_to_sm_copy( tripoint( lx, ly, 0 ) ) ); | |
| g->u.setx( 2 ); | |
| g->u.sety( 4 ); | |
| // This shifts the view to center the players pos | |
| g->update_map( g->u ); | |
| return true; | |
| } | |
| void tutorial_game::per_turn() | |
| { | |
| if( calendar::turn == HOURS( 12 ) ) { | |
| add_message( LESSON_INTRO ); | |
| add_message( LESSON_INTRO ); | |
| } else if( calendar::turn == HOURS( 12 ) + 3 ) { | |
| add_message( LESSON_INTRO ); | |
| } | |
| if( g->light_level( g->u.posz() ) == 1 ) { | |
| if( g->u.has_amount( "flashlight", 1 ) ) { | |
| add_message( LESSON_DARK ); | |
| } else { | |
| add_message( LESSON_DARK_NO_FLASH ); | |
| } | |
| } | |
| if( g->u.get_pain() > 0 ) { | |
| add_message( LESSON_PAIN ); | |
| } | |
| if( g->u.recoil >= MIN_RECOIL ) { | |
| add_message( LESSON_RECOIL ); | |
| } | |
| if( !tutorials_seen[LESSON_BUTCHER] ) { | |
| for( size_t i = 0; i < g->m.i_at( g->u.posx(), g->u.posy() ).size(); i++ ) { | |
| if( g->m.i_at( g->u.posx(), g->u.posy() )[i].is_corpse() ) { | |
| add_message( LESSON_BUTCHER ); | |
| i = g->m.i_at( g->u.posx(), g->u.posy() ).size(); | |
| } | |
| } | |
| } | |
| bool showed_message = false; | |
| for( int x = g->u.posx() - 1; x <= g->u.posx() + 1 && !showed_message; x++ ) { | |
| for( int y = g->u.posy() - 1; y <= g->u.posy() + 1 && !showed_message; y++ ) { | |
| if( g->m.ter( x, y ) == t_door_o ) { | |
| add_message( LESSON_OPEN ); | |
| showed_message = true; | |
| } else if( g->m.ter( x, y ) == t_door_c ) { | |
| add_message( LESSON_CLOSE ); | |
| showed_message = true; | |
| } else if( g->m.ter( x, y ) == t_window ) { | |
| add_message( LESSON_SMASH ); | |
| showed_message = true; | |
| } else if( g->m.furn( x, y ) == f_rack && !g->m.i_at( x, y ).empty() ) { | |
| add_message( LESSON_EXAMINE ); | |
| showed_message = true; | |
| } else if( g->m.ter( x, y ) == t_stairs_down ) { | |
| add_message( LESSON_STAIRS ); | |
| showed_message = true; | |
| } else if( g->m.ter( x, y ) == t_water_sh ) { | |
| add_message( LESSON_PICKUP_WATER ); | |
| showed_message = true; | |
| } | |
| } | |
| } | |
| if( !g->m.i_at( g->u.posx(), g->u.posy() ).empty() ) { | |
| add_message( LESSON_PICKUP ); | |
| } | |
| } | |
| void tutorial_game::pre_action( action_id &act ) | |
| { | |
| switch( act ) { | |
| case ACTION_SAVE: | |
| case ACTION_QUICKSAVE: | |
| popup( _( "You're saving a tutorial - the tutorial world lacks certain features of normal worlds. " | |
| "Weird things might happen when you load this save. You have been warned." ) ); | |
| break; | |
| default: | |
| // Other actions are fine. | |
| break; | |
| } | |
| } | |
| void tutorial_game::post_action( action_id act ) | |
| { | |
| switch( act ) { | |
| case ACTION_RELOAD: | |
| if( g->u.weapon.is_gun() && !tutorials_seen[LESSON_GUN_FIRE] ) { | |
| g->summon_mon( mon_zombie, tripoint( g->u.posx(), g->u.posy() - 6, g->u.posz() ) ); | |
| g->summon_mon( mon_zombie, tripoint( g->u.posx() + 2, g->u.posy() - 5, g->u.posz() ) ); | |
| g->summon_mon( mon_zombie, tripoint( g->u.posx() - 2, g->u.posy() - 5, g->u.posz() ) ); | |
| add_message( LESSON_GUN_FIRE ); | |
| } | |
| break; | |
| case ACTION_OPEN: | |
| add_message( LESSON_CLOSE ); | |
| break; | |
| case ACTION_CLOSE: | |
| add_message( LESSON_SMASH ); | |
| break; | |
| case ACTION_USE: | |
| if( g->u.has_amount( "grenade_act", 1 ) ) { | |
| add_message( LESSON_ACT_GRENADE ); | |
| } | |
| for( int x = g->u.posx() - 1; x <= g->u.posx() + 1; x++ ) { | |
| for( int y = g->u.posy() - 1; y <= g->u.posy() + 1; y++ ) { | |
| if( g->m.tr_at( {x, y, g->u.posz()} ).id == trap_str_id( "tr_bubblewrap" ) ) | |
| add_message( LESSON_ACT_BUBBLEWRAP ); | |
| } | |
| } | |
| break; | |
| case ACTION_EAT: | |
| if( g->u.last_item == "codeine" ) { | |
| add_message( LESSON_TOOK_PAINKILLER ); | |
| } else if( g->u.last_item == "cig" ) { | |
| add_message( LESSON_TOOK_CIG ); | |
| } else if( g->u.last_item == "water" ) { | |
| add_message( LESSON_DRANK_WATER ); | |
| } | |
| break; | |
| case ACTION_WEAR: { | |
| item it( g->u.last_item, 0 ); | |
| if( it.is_armor() ) { | |
| if( it.get_coverage() >= 2 || it.get_thickness() >= 2 ) { | |
| add_message( LESSON_WORE_ARMOR ); | |
| } | |
| if( it.get_storage() >= units::from_liter( 5 ) ) { | |
| add_message( LESSON_WORE_STORAGE ); | |
| } | |
| if( it.get_env_resist() >= 2 ) { | |
| add_message( LESSON_WORE_MASK ); | |
| } | |
| } | |
| } | |
| break; | |
| case ACTION_WIELD: | |
| if( g->u.weapon.is_gun() ) { | |
| add_message( LESSON_GUN_LOAD ); | |
| } | |
| break; | |
| case ACTION_EXAMINE: | |
| add_message( LESSON_INTERACT ); | |
| // Fall through to... | |
| case ACTION_PICKUP: { | |
| item it( g->u.last_item, 0 ); | |
| if( it.is_armor() ) { | |
| add_message( LESSON_GOT_ARMOR ); | |
| } else if( it.is_gun() ) { | |
| add_message( LESSON_GOT_GUN ); | |
| } else if( it.is_ammo() ) { | |
| add_message( LESSON_GOT_AMMO ); | |
| } else if( it.is_tool() ) { | |
| add_message( LESSON_GOT_TOOL ); | |
| } else if( it.is_food() ) { | |
| add_message( LESSON_GOT_FOOD ); | |
| } else if( it.is_melee() ) { | |
| add_message( LESSON_GOT_WEAPON ); | |
| } | |
| } | |
| break; | |
| default: //TODO: add more actions here | |
| break; | |
| } | |
| } | |
| void tutorial_game::add_message( tut_lesson lesson ) | |
| { | |
| // Cycle through intro lessons | |
| if( lesson == LESSON_INTRO ) { | |
| while( lesson != NUM_LESSONS && tutorials_seen[lesson] ) { | |
| switch( lesson ) { | |
| case LESSON_INTRO: | |
| lesson = LESSON_MOVE; | |
| break; | |
| case LESSON_MOVE: | |
| lesson = LESSON_LOOK; | |
| break; | |
| default: | |
| lesson = NUM_LESSONS; | |
| break; | |
| } | |
| } | |
| if( lesson == NUM_LESSONS ) { | |
| return; | |
| } | |
| } | |
| if( tutorials_seen[lesson] ) { | |
| return; | |
| } | |
| tutorials_seen[lesson] = true; | |
| popup( tut_text[lesson], PF_ON_TOP ); | |
| g->refresh_all(); | |
| } | |
| void load_tutorial_messages( JsonObject &jo ) | |
| { | |
| // loading them all at once, as they have to be in exact order | |
| tut_text.clear(); | |
| JsonArray messages = jo.get_array( "messages" ); | |
| while( messages.has_more() ) { | |
| tut_text.push_back( _( messages.next_string().c_str() ) ); | |
| } | |
| } | |
| void clear_tutorial_messages() | |
| { | |
| tut_text.clear(); | |
| } |