bool player::eat( item &food, bool force ) { if( !food.is_food() ) { return false; } // Check if it's rotten before eating! food.calc_rot( global_square_location() ); const auto ret = force ? can_eat( food ) : will_eat( food, is_player() ); if( !ret.success() ) { return false; } if( food.type->has_use() ) { if( food.type->invoke( *this, food, pos() ) <= 0 ) { return false; } } // Note: the block below assumes we decided to eat it // No coming back from here const bool hibernate = has_active_mutation( trait_id( "HIBERNATE" ) ); const int nutr = nutrition_for( food ); const int quench = food.type->comestible->quench; const bool spoiled = food.rotten(); // The item is solid food const bool chew = food.type->comestible->comesttype == "FOOD" || food.has_flag( "USE_EAT_VERB" ); // This item is a drink and not a solid food (and not a thick soup) const bool drinkable = !chew && food.type->comestible->comesttype == "DRINK"; // If neither of the above is true then it's a drug and shouldn't get mealtime penalty/bonus if( hibernate && ( get_hunger() > -60 && get_thirst() > -60 ) && ( get_hunger() - nutr < -60 || get_thirst() - quench < -60 ) ) { add_memorial_log( pgettext( "memorial_male", "Began preparing for hibernation." ), pgettext( "memorial_female", "Began preparing for hibernation." ) ); add_msg_if_player( _( "You've begun stockpiling calories and liquid for hibernation. You get the feeling that you should prepare for bed, just in case, but...you're hungry again, and you could eat a whole week's worth of food RIGHT NOW." ) ); } const bool will_vomit = get_hunger() < 0 && nutr >= 5 && !has_trait( trait_id( "GOURMAND" ) ) && !hibernate && !has_trait( trait_id( "SLIMESPAWNER" ) ) && !has_trait( trait_id( "EATHEALTH" ) ) && rng( -200, 0 ) > get_hunger() - nutr; const bool saprophage = has_trait( trait_id( "SAPROPHAGE" ) ); if( spoiled && !saprophage ) { add_msg_if_player( m_bad, _( "Ick, this %s doesn't taste so good..." ), food.tname().c_str() ); if( !has_trait( trait_id( "SAPROVORE" ) ) && !has_trait( trait_id( "EATDEAD" ) ) && ( !has_bionic( bio_digestion ) || one_in( 3 ) ) ) { add_effect( effect_foodpoison, rng( 60, ( nutr + 1 ) * 60 ) ); } consume_effects( food ); } else if( spoiled && saprophage ) { add_msg_if_player( m_good, _( "Mmm, this %s tastes delicious..." ), food.tname().c_str() ); consume_effects( food ); } else { consume_effects( food ); } const bool amorphous = has_trait( trait_id( "AMORPHOUS" ) ); int mealtime = 250; if( drinkable || chew ) { // Those bonuses/penalties only apply to food // Not to smoking weed or applying bandages! if( has_trait( trait_id( "MOUTH_TENTACLES" ) ) || has_trait( trait_id( "MANDIBLES" ) ) ) { mealtime /= 2; } else if( has_trait( trait_id( "GOURMAND" ) ) ) { // Don't stack those two - that would be 25 moves per item mealtime -= 100; } if( has_trait( trait_id( "BEAK_HUM" ) ) && !drinkable ) { mealtime += 200; // Much better than PROBOSCIS but still optimized for fluids } else if( has_trait( trait_id( "SABER_TEETH" ) ) ) { mealtime += 250; // They get In The Way } if( amorphous ) { mealtime *= 1.1; // Minor speed penalty for having to flow around it // rather than just grab & munch } } moves -= mealtime; // If it's poisonous... poison us. // TODO: Move this to a flag if( food.poison > 0 && !has_trait( trait_id( "EATPOISON" ) ) && !has_trait( trait_id( "EATDEAD" ) ) ) { if( food.poison >= rng( 2, 4 ) ) { add_effect( effect_poison, food.poison * 100 ); } add_effect( effect_foodpoison, food.poison * 300 ); } if( amorphous ) { add_msg_player_or_npc( _( "You assimilate your %s." ), _( "<npcname> assimilates a %s." ), food.tname().c_str() ); } else if( drinkable ) { add_msg_player_or_npc( _( "You drink your %s." ), _( "<npcname> drinks a %s." ), food.tname().c_str() ); } else if( chew ) { add_msg_player_or_npc( _( "You eat your %s." ), _( "<npcname> eats a %s." ), food.tname().c_str() ); } if( item::find_type( food.type->comestible->tool )->tool ) { // Tools like lighters get used use_charges( food.type->comestible->tool, 1 ); } if( has_bionic( bio_ethanol ) && food.type->can_use( "ALCOHOL" ) ) { charge_power( rng( 50, 200 ) ); } if( has_bionic( bio_ethanol ) && food.type->can_use( "ALCOHOL_WEAK" ) ) { charge_power( rng( 25, 100 ) ); } if( has_bionic( bio_ethanol ) && food.type->can_use( "ALCOHOL_STRONG" ) ) { charge_power( rng( 75, 300 ) ); } if( food.has_flag( "CANNIBALISM" ) ) { // Sapiovores don't recognize humans as the same species. // But let them possibly feel cool about eating sapient stuff - treat like psycho const bool cannibal = has_trait( trait_id( "CANNIBAL" ) ); const bool psycho = has_trait( trait_id( "PSYCHOPATH" ) ) || has_trait( trait_id( "SAPIOVORE" ) ); const bool spiritual = has_trait( trait_id( "SPIRITUAL" ) ); if( cannibal && psycho && spiritual ) { add_msg_if_player( m_good, _( "You feast upon the human flesh, and in doing so, devour their spirit." ) ); // You're not really consuming anything special; you just think you are. add_morale( MORALE_CANNIBAL, 25, 300 ); } else if( cannibal && psycho ) { add_msg_if_player( m_good, _( "You feast upon the human flesh." ) ); add_morale( MORALE_CANNIBAL, 15, 200 ); } else if( cannibal && spiritual ) { add_msg_if_player( m_good, _( "You consume the sacred human flesh." ) ); // Boosted because you understand the philosophical implications of your actions, and YOU LIKE THEM. add_morale( MORALE_CANNIBAL, 15, 200 ); } else if( cannibal ) { add_msg_if_player( m_good, _( "You indulge your shameful hunger." ) ); add_morale( MORALE_CANNIBAL, 10, 50 ); } else if( psycho && spiritual ) { add_msg_if_player( _( "You greedily devour the taboo meat." ) ); // Small bonus for violating a taboo. add_morale( MORALE_CANNIBAL, 5, 50 ); } else if( psycho ) { add_msg_if_player( _( "Meh. You've eaten worse." ) ); } else if( spiritual ) { add_msg_if_player( m_bad, _( "This is probably going to count against you if there's still an afterlife." ) ); add_morale( MORALE_CANNIBAL, -60, -400, 600, 300 ); } else { add_msg_if_player( m_bad, _( "You feel horrible for eating a person." ) ); add_morale( MORALE_CANNIBAL, -60, -400, 600, 300 ); } } // Allergy check const auto allergy = allergy_type( food ); if( allergy != MORALE_NULL ) { add_msg_if_player( m_bad, _( "Yuck! How can anybody eat this stuff?" ) ); add_morale( allergy, -75, -400, 300, 240 ); } // Carnivores CAN eat junk food, but they won't like it much. // Pizza-scraping happens in consume_effects. if( has_trait( trait_id( "CARNIVORE" ) ) && food.has_flag( "ALLERGEN_JUNK" ) && !food.has_flag( "CARNIVORE_OK" ) ) { add_msg_if_player( m_bad, _( "Your stomach begins gurgling and you feel bloated and ill." ) ); add_morale( MORALE_NO_DIGEST, -25, -125, 300, 240 ); } if( !spoiled && chew && has_trait( trait_id( "SAPROPHAGE" ) ) ) { // It's OK to *drink* things that haven't rotted. Alternative is to ban water. D: add_msg_if_player( m_bad, _( "Your stomach begins gurgling and you feel bloated and ill." ) ); add_morale( MORALE_NO_DIGEST, -75, -400, 300, 240 ); } if( food.has_flag( "URSINE_HONEY" ) && ( !crossed_threshold() || has_trait( trait_id( "THRESH_URSINE" ) ) ) && mutation_category_level["MUTCAT_URSINE"] > 40 ) { //Need at least 5 bear mutations for effect to show, to filter out mutations in common with other mutcats int honey_fun = has_trait( trait_id( "THRESH_URSINE" ) ) ? std::min( mutation_category_level["MUTCAT_URSINE"] / 8, 20 ) : mutation_category_level["MUTCAT_URSINE"] / 12; if( honey_fun < 10 ) { add_msg_if_player( m_good, _( "You find the sweet taste of honey surprisingly palatable." ) ); } else { add_msg_if_player( m_good, _( "You feast upon the sweet honey." ) ); } add_morale( MORALE_HONEY, honey_fun, 100 ); } if( will_vomit ) { vomit(); } // chance to become parasitised if( !( has_bionic( bio_digestion ) || has_trait( trait_id( "PARAIMMUNE" ) ) ) ) { if( food.type->comestible->parasites > 0 && one_in( food.type->comestible->parasites ) ) { switch( rng( 0, 3 ) ) { case 0: if( !has_trait( trait_id( "EATHEALTH" ) ) ) { add_effect( effect_tapeworm, 1, num_bp, true ); } break; case 1: if( !has_trait( trait_id( "ACIDBLOOD" ) ) ) { add_effect( effect_bloodworms, 1, num_bp, true ); } break; case 2: add_effect( effect_brainworms, 1, num_bp, true ); break; case 3: add_effect( effect_paincysts, 1, num_bp, true ); } } } for( const auto &v : this->vitamins_from( food ) ) { auto qty = has_effect( effect_tapeworm ) ? v.second / 2 : v.second; // can never develop hypervitaminosis from consuming food vitamin_mod( v.first, qty ); } food.mod_charges( -1 ); return true; }
void function_minimizer::pvm_master_mcmc_routine(int nmcmc,int iseed0,double dscale, int restart_flag) { uostream * pofs_psave=NULL; dmatrix mcmc_display_matrix; int mcmc_save_index=1; int mcmc_wrap_flag=0; int mcmc_gui_length=10000; int no_sd_mcmc=0; int on2=-1; if ( (on2=option_match(ad_comm::argc,ad_comm::argv,"-nosdmcmc"))>-1) no_sd_mcmc=1; if (stddev_params::num_stddev_params==0) { cerr << " You must declare at least one object of type sdreport " << endl << " to do the mcmc calculations" << endl; return; } { //ofstream of_bf("testbf"); //if (adjm_ptr) set_labels_for_mcmc(); ivector number_offsets; dvector lkvector; //double current_bf=0; double lcurrent_bf=0; double size_scale=1.0; double total_spread=200; //double total_spread=2500; uostream * pofs_sd = NULL; int nvar=initial_params::nvarcalc(); // get the number of active parameters int scov_option=0; dmatrix s_covar; dvector s_mean; int on=-1; int ncsim=25000; int nslots=800; //int nslots=3600; int initial_nsim=4800; int ntmp=0; int ncor=0; double bfsum=0; int ibfcount=0; double llbest; double lbmax; //if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcscov",ntmp))>-1) //{ scov_option=1; s_covar.allocate(1,nvar,1,nvar); s_mean.allocate(1,nvar); s_mean.initialize(); s_covar.initialize(); int ndvar=stddev_params::num_stddev_calc(); int numdvar=stddev_params::num_stddev_number_calc(); /* if (adjm_ptr) { mcmc_display_matrix.allocate(1,numdvar,1,mcmc_gui_length); number_offsets.allocate(1,numdvar); number_offsets=stddev_params::copy_all_number_offsets(); } */ dvector x(1,nvar); dvector scale(1,nvar); dmatrix values; int have_hist_flag=0; initial_params::xinit(x); dvector pen_vector(1,nvar); { initial_params::reset(dvar_vector(x),pen_vector); cout << pen_vector << endl << endl; } initial_params::mc_phase=0; initial_params::stddev_scale(scale,x); initial_params::mc_phase=1; dvector bmn(1,nvar); dvector mean_mcmc_values(1,ndvar); dvector s(1,ndvar); dvector h(1,ndvar); //dvector h; dvector square_mcmc_values(1,ndvar); square_mcmc_values.initialize(); mean_mcmc_values.initialize(); bmn.initialize(); int use_empirical_flag=0; int diag_option=0; int topt=0; if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcdiag"))>-1) { diag_option=1; cout << " Setting covariance matrix to diagonal with entries " << dscale << endl; } dmatrix S(1,nvar,1,nvar); dvector sscale(1,nvar); if (!diag_option) { int on,nopt; int rescale_bounded_flag=0; double rescale_bounded_power=0.5; if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcrb",nopt))>-1) { if (nopt) { int iii=atoi(ad_comm::argv[on+1]); if (iii < 1 || iii > 9) { cerr << " -mcrb argument must be integer between 1 and 9 --" " using default of 5" << endl; rescale_bounded_power=0.5; } else rescale_bounded_power=iii/10.0; } else { rescale_bounded_power=0.5; } rescale_bounded_flag=1; } if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcec"))>-1) { use_empirical_flag=1; } if (use_empirical_flag) { read_empirical_covariance_matrix(nvar,S,ad_comm::adprogram_name); } else if (!rescale_bounded_flag) { int tmp; read_covariance_matrix(S,nvar,tmp,sscale); } else { read_hessian_matrix_and_scale1(nvar,S,rescale_bounded_power, mcmc2_flag); //read_hessian_matrix_and_scale(nvar,S,pen_vector); } { // scale covariance matrix for model space dmatrix tmp(1,nvar,1,nvar); for (int i=1;i<=nvar;i++) { tmp(i,i)=S(i,i)*(scale(i)*scale(i)); for (int j=1;j<i;j++) { tmp(i,j)=S(i,j)*(scale(i)*scale(j)); tmp(j,i)=tmp(i,j); } } S=tmp; } } else { S.initialize(); for (int i=1;i<=nvar;i++) { S(i,i)=dscale; } } cout << sort(eigenvalues(S)) << endl; dmatrix chd = choleski_decomp( (dscale*2.4/sqrt(double(nvar))) * S); dmatrix chdinv=inv(chd); int sgn; dmatrix symbds(1,2,1,nvar); initial_params::set_all_simulation_bounds(symbds); ofstream ofs_sd1((char*)(ad_comm::adprogram_name + adstring(".mc2"))); { long int iseed=0; int number_sims; if (nmcmc<=0) { number_sims= 100000; } else { number_sims= nmcmc; } //cin >> iseed; if (iseed0<=0) { iseed=-36519; } else { iseed=-iseed0; } if (iseed>0) { iseed=-iseed; } cout << "Initial seed value " << iseed << endl; random_number_generator rng(iseed); rng.better_rand(); //better_rand(iseed); double lprob=0.0; double lpinv=0.0; double lprob3=0.0; // get lower and upper bounds independent_variables y(1,nvar); independent_variables parsave(1,nvar); // read in the mcmc values to date int ii=1; dmatrix hist; if (restart_flag) { int tmp=0; if (!no_sd_mcmc) { hist.allocate(1,ndvar,-nslots,nslots); tmp=read_hist_data(hist,h,mean_mcmc_values,s,parsave,iseed, size_scale); values.allocate(1,ndvar,-nslots,nslots); for (int i=1;i<=ndvar;i++) { values(i).fill_seqadd(mean_mcmc_values(i)-0.5*total_spread*s(i) +.5*h(i),h(i)); } } if (iseed>0) { iseed=-iseed; } double br=rng.better_rand(); if (tmp) have_hist_flag=1; chd=size_scale*chd; chdinv=chdinv/size_scale; } else { int on=-1; int nopt=0; if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcpin",nopt))>-1) { if (nopt) { cifstream cif((char *)ad_comm::argv[on+1]); if (!cif) { cerr << "Error trying to open mcmc par input file " << ad_comm::argv[on+1] << endl; exit(1); } cif >> parsave; if (!cif) { cerr << "Error reading from mcmc par input file " << ad_comm::argv[on+1] << endl; exit(1); } } else { cerr << "Illegal option with -mcpin" << endl; } } else { ii=1; initial_params::copy_all_values(parsave,ii); } } ii=1; initial_params::restore_all_values(parsave,ii); gradient_structure::set_NO_DERIVATIVES(); ofstream ogs("sims"); ogs << nvar << " " << number_sims << endl; initial_params::xinit(y); send_int_to_slaves(1); double llc=-pvm_master_get_monte_carlo_value(nvar,y); send_int_to_slaves(1); llbest=-pvm_master_get_monte_carlo_value(nvar,y); lbmax=llbest; // store current mcmc variable values in param_values //dmatrix store_mcmc_values(1,number_sims,1,ndvar); #if defined(USE_BAYES_FACTORS) lkvector.allocate(1,number_sims); #endif dvector mcmc_values(1,ndvar); dvector mcmc_number_values; //if (adjm_ptr) mcmc_number_values.allocate(1,numdvar); int offs=1; stddev_params::copy_all_values(mcmc_values,offs); /* if (adjm_ptr) { offs=1; stddev_params::copy_all_number_values(mcmc_number_values,offs); } */ int change_ball=2500; int nopt; if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcscale",nopt))>-1) { if (nopt) { int iii=atoi(ad_comm::argv[on+1]); if (iii <=0) { cerr << " Invalid option following command line option -mcball -- " << endl << " ignored" << endl; } else change_ball=iii; } } int iac=0; int liac=0; int isim=0; int itmp=0; double logr; int u_option=0; double ll; int s_option=1; int psvflag=0; if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcu"))>-1) { u_option=1; } if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcnoscale"))>-1) { s_option=0; } //cout << llc << " " << llc << endl; int iac_old=0; int i_old=0; { if (!restart_flag) { pofs_sd = new uostream((char*)(ad_comm::adprogram_name + adstring(".mcm"))); } int mcsave_flag=0; int mcrestart_flag=option_match(ad_comm::argc,ad_comm::argv,"-mcr"); if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcsave"))>-1) { int jj=(int)atof(ad_comm::argv[on+1]); if (jj <=0) { cerr << " Invalid option following command line option -mcsave -- " << endl; } else { mcsave_flag=jj; if ( mcrestart_flag>-1) { // check that nvar is correct { uistream uis((char*)(ad_comm::adprogram_name + adstring(".psv"))); if (!uis) { cerr << "Error trying to open file" << ad_comm::adprogram_name + adstring(".psv") << " for mcrestart" << endl; cerr << " I am starting a new file " << endl; psvflag=1; } else { int nv1; uis >> nv1; if (nv1 !=nvar) { cerr << "wrong number of independent variables in" << ad_comm::adprogram_name + adstring(".psv") << cerr << " I am starting a new file " << endl; psvflag=1; } } } if (!psvflag) { pofs_psave= new uostream( (char*)(ad_comm::adprogram_name + adstring(".psv")),ios::app); } else { pofs_psave= new uostream((char*)(ad_comm::adprogram_name + adstring(".psv"))); } } else {
void mission_start::place_npc_software(mission *miss) { npc* dev = g->find_npc(miss->npc_id); if (dev == NULL) { debugmsg("Couldn't find NPC! %d", miss->npc_id); return; } g->u.i_add( item("usb_drive", 0) ); add_msg(_("%s gave you a USB drive."), dev->name.c_str()); std::string type = "house"; switch (dev->myclass) { case NC_HACKER: miss->item_id = "software_hacking"; break; case NC_DOCTOR: miss->item_id = "software_medical"; type = "s_pharm"; miss->follow_up = MISSION_GET_ZOMBIE_BLOOD_ANAL; break; case NC_SCIENTIST: miss->item_id = "software_math"; break; default: miss->item_id = "software_useless"; } int dist = 0; point place; if (type == "house") { place = random_house_in_closest_city(); } else { place = overmap_buffer.find_closest(dev->global_omt_location(), type, dist, false); } miss->target = place; overmap_buffer.reveal(place, 6, g->get_levz()); tinymap compmap; compmap.load(place.x * 2, place.y * 2, g->get_levz(), false); point comppoint; oter_id oter = overmap_buffer.ter(place.x, place.y, 0); if( is_ot_type("house", oter) || is_ot_type("s_pharm", oter) || oter == "" ) { std::vector<point> valid; for (int x = 0; x < SEEX * 2; x++) { for (int y = 0; y < SEEY * 2; y++) { if (compmap.ter(x, y) == t_floor && compmap.furn(x, y) == f_null) { bool okay = false; int wall = 0; for (int x2 = x - 1; x2 <= x + 1 && !okay; x2++) { for (int y2 = y - 1; y2 <= y + 1 && !okay; y2++) { if (compmap.furn(x2, y2) == f_bed || compmap.furn(x2, y2) == f_dresser) { okay = true; valid.push_back( point(x, y) ); } if ( compmap.has_flag_ter("WALL", x2, y2) ) { wall++; } } } if ( wall == 5 ) { if ( compmap.is_last_ter_wall( true, x, y, SEEX * 2, SEEY * 2, NORTH ) && compmap.is_last_ter_wall( true, x, y, SEEX * 2, SEEY * 2, SOUTH ) && compmap.is_last_ter_wall( true, x, y, SEEX * 2, SEEY * 2, WEST ) && compmap.is_last_ter_wall( true, x, y, SEEX * 2, SEEY * 2, EAST ) ) { valid.push_back( point(x, y) ); } } } } } if (valid.empty()) { comppoint = point( rng(6, SEEX * 2 - 7), rng(6, SEEY * 2 - 7) ); } else { comppoint = valid[rng(0, valid.size() - 1)]; } } compmap.ter_set(comppoint.x, comppoint.y, t_console); computer *tmpcomp = compmap.add_computer(comppoint.x, comppoint.y, string_format(_("%s's Terminal"), dev->name.c_str()), 0); tmpcomp->mission_id = miss->uid; tmpcomp->add_option(_("Download Software"), COMPACT_DOWNLOAD_SOFTWARE, 0); compmap.save(); }
bool monster::move_to( const tripoint &p, bool force, const float stagger_adjustment ) { const bool digs = digging(); const bool flies = has_flag( MF_FLIES ); const bool on_ground = !digs && !flies; const bool climbs = has_flag( MF_CLIMBS ) && g->m.has_flag( TFLAG_NO_FLOOR, p ); // Allows climbing monsters to move on terrain with movecost <= 0 Creature *critter = g->critter_at( p, is_hallucination() ); if( g->m.has_flag( "CLIMBABLE", p ) ) { if( g->m.impassable( p ) && critter == nullptr ) { if( flies ) { moves -= 100; force = true; if( g->u.sees( *this ) ) { add_msg( _( "The %1$s flies over the %2$s." ), name().c_str(), g->m.has_flag_furn( "CLIMBABLE", p ) ? g->m.furnname( p ).c_str() : g->m.tername( p ).c_str() ); } } else if( has_flag( MF_CLIMBS ) ) { moves -= 150; force = true; if( g->u.sees( *this ) ) { add_msg( _( "The %1$s climbs over the %2$s." ), name().c_str(), g->m.has_flag_furn( "CLIMBABLE", p ) ? g->m.furnname( p ).c_str() : g->m.tername( p ).c_str() ); } } } } if( critter != nullptr && !force ) { return false; } // Make sure that we can move there, unless force is true. if( !force && !can_move_to( p ) ) { return false; } if( !force ) { // This adjustment is to make it so that monster movement speed relative to the player // is consistent even if the monster stumbles, // and the same regardless of the distance measurement mode. // Note: Keep this as float here or else it will cancel valid moves const float cost = stagger_adjustment * ( float )( climbs ? calc_climb_cost( pos(), p ) : calc_movecost( pos(), p ) ); if( cost > 0.0f ) { moves -= ( int )ceil( cost ); } else { return false; } } //Check for moving into/out of water bool was_water = g->m.is_divable( pos() ); bool will_be_water = on_ground && can_submerge() && g->m.is_divable( p ); if( was_water && !will_be_water && g->u.sees( p ) ) { //Use more dramatic messages for swimming monsters add_msg( m_warning, _( "A %1$s %2$s from the %3$s!" ), name().c_str(), has_flag( MF_SWIMS ) || has_flag( MF_AQUATIC ) ? _( "leaps" ) : _( "emerges" ), g->m.tername( pos() ).c_str() ); } else if( !was_water && will_be_water && g->u.sees( p ) ) { add_msg( m_warning, _( "A %1$s %2$s into the %3$s!" ), name().c_str(), has_flag( MF_SWIMS ) || has_flag( MF_AQUATIC ) ? _( "dives" ) : _( "sinks" ), g->m.tername( p ).c_str() ); } setpos( p ); footsteps( p ); underwater = will_be_water; if( is_hallucination() ) { //Hallucinations don't do any of the stuff after this point return true; } // TODO: Make tanks stop taking damage from rubble, because it's just silly if( type->size != MS_TINY && on_ground ) { if( g->m.has_flag( "SHARP", pos() ) && !one_in( 4 ) ) { apply_damage( nullptr, bp_torso, rng( 1, 10 ) ); } if( g->m.has_flag( "ROUGH", pos() ) && one_in( 6 ) ) { apply_damage( nullptr, bp_torso, rng( 1, 2 ) ); } } if( g->m.has_flag( "UNSTABLE", p ) && on_ground ) { add_effect( effect_bouldering, 1, num_bp, true ); } else if( has_effect( effect_bouldering ) ) { remove_effect( effect_bouldering ); } g->m.creature_on_trap( *this ); if( !will_be_water && ( has_flag( MF_DIGS ) || has_flag( MF_CAN_DIG ) ) ) { underwater = g->m.has_flag( "DIGGABLE", pos() ); } // Diggers turn the dirt into dirtmound if( digging() ) { int factor = 0; switch( type->size ) { case MS_TINY: factor = 100; break; case MS_SMALL: factor = 30; break; case MS_MEDIUM: factor = 6; break; case MS_LARGE: factor = 3; break; case MS_HUGE: factor = 1; break; } if( one_in( factor ) ) { g->m.ter_set( pos(), t_dirtmound ); } } // Acid trail monsters leave... a trail of acid if( has_flag( MF_ACIDTRAIL ) ) { g->m.add_field( pos(), fd_acid, 3, 0 ); } if( has_flag( MF_SLUDGETRAIL ) ) { for( const tripoint &sludge_p : g->m.points_in_radius( pos(), 1 ) ) { const int fstr = 3 - ( abs( sludge_p.x - posx() ) + abs( sludge_p.y - posy() ) ); if( fstr >= 2 ) { g->m.add_field( sludge_p, fd_sludge, fstr, 0 ); } } } return true; }
/*! \brief Do test particle insertion. \copydoc integrator_t (FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog, int nfile, const t_filenm fnm[], const gmx_output_env_t *oenv, gmx_bool bVerbose, int nstglobalcomm, gmx_vsite_t *vsite, gmx_constr_t constr, int stepout, t_inputrec *inputrec, gmx_mtop_t *top_global, t_fcdata *fcd, t_state *state_global, t_mdatoms *mdatoms, t_nrnb *nrnb, gmx_wallcycle_t wcycle, gmx_edsam_t ed, t_forcerec *fr, int repl_ex_nst, int repl_ex_nex, int repl_ex_seed, real cpt_period, real max_hours, int imdport, unsigned long Flags, gmx_walltime_accounting_t walltime_accounting) */ double do_tpi(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog, int nfile, const t_filenm fnm[], const gmx_output_env_t *oenv, gmx_bool bVerbose, int gmx_unused nstglobalcomm, gmx_vsite_t gmx_unused *vsite, gmx_constr_t gmx_unused constr, int gmx_unused stepout, t_inputrec *inputrec, gmx_mtop_t *top_global, t_fcdata *fcd, t_state *state_global, t_mdatoms *mdatoms, t_nrnb *nrnb, gmx_wallcycle_t wcycle, gmx_edsam_t gmx_unused ed, t_forcerec *fr, int gmx_unused repl_ex_nst, int gmx_unused repl_ex_nex, int gmx_unused repl_ex_seed, real gmx_unused cpt_period, real gmx_unused max_hours, int gmx_unused imdport, unsigned long gmx_unused Flags, gmx_walltime_accounting_t walltime_accounting) { gmx_localtop_t *top; gmx_groups_t *groups; gmx_enerdata_t *enerd; rvec *f; real lambda, t, temp, beta, drmax, epot; double embU, sum_embU, *sum_UgembU, V, V_all, VembU_all; t_trxstatus *status; t_trxframe rerun_fr; gmx_bool bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS; tensor force_vir, shake_vir, vir, pres; int cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e; rvec *x_mol; rvec mu_tot, x_init, dx, x_tp; int nnodes, frame; gmx_int64_t frame_step_prev, frame_step; gmx_int64_t nsteps, stepblocksize = 0, step; gmx_int64_t seed; int i; FILE *fp_tpi = NULL; char *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN]; double dbl, dump_ener; gmx_bool bCavity; int nat_cavity = 0, d; real *mass_cavity = NULL, mass_tot; int nbin; double invbinw, *bin, refvolshift, logV, bUlogV; real prescorr, enercorr, dvdlcorr; gmx_bool bEnergyOutOfBounds; const char *tpid_leg[2] = {"direct", "reweighted"}; /* Since there is no upper limit to the insertion energies, * we need to set an upper limit for the distribution output. */ real bU_bin_limit = 50; real bU_logV_bin_limit = bU_bin_limit + 10; if (inputrec->cutoff_scheme == ecutsVERLET) { gmx_fatal(FARGS, "TPI does not work (yet) with the Verlet cut-off scheme"); } nnodes = cr->nnodes; top = gmx_mtop_generate_local_top(top_global, inputrec->efep != efepNO); groups = &top_global->groups; bCavity = (inputrec->eI == eiTPIC); if (bCavity) { ptr = getenv("GMX_TPIC_MASSES"); if (ptr == NULL) { nat_cavity = 1; } else { /* Read (multiple) masses from env var GMX_TPIC_MASSES, * The center of mass of the last atoms is then used for TPIC. */ nat_cavity = 0; while (sscanf(ptr, "%20lf%n", &dbl, &i) > 0) { srenew(mass_cavity, nat_cavity+1); mass_cavity[nat_cavity] = dbl; fprintf(fplog, "mass[%d] = %f\n", nat_cavity+1, mass_cavity[nat_cavity]); nat_cavity++; ptr += i; } if (nat_cavity == 0) { gmx_fatal(FARGS, "Found %d masses in GMX_TPIC_MASSES", nat_cavity); } } } /* init_em(fplog,TPI,inputrec,&lambda,nrnb,mu_tot, state_global->box,fr,mdatoms,top,cr,nfile,fnm,NULL,NULL);*/ /* We never need full pbc for TPI */ fr->ePBC = epbcXYZ; /* Determine the temperature for the Boltzmann weighting */ temp = inputrec->opts.ref_t[0]; if (fplog) { for (i = 1; (i < inputrec->opts.ngtc); i++) { if (inputrec->opts.ref_t[i] != temp) { fprintf(fplog, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); fprintf(stderr, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); } } fprintf(fplog, "\n The temperature for test particle insertion is %.3f K\n\n", temp); } beta = 1.0/(BOLTZ*temp); /* Number of insertions per frame */ nsteps = inputrec->nsteps; /* Use the same neighborlist with more insertions points * in a sphere of radius drmax around the initial point */ /* This should be a proper mdp parameter */ drmax = inputrec->rtpi; /* An environment variable can be set to dump all configurations * to pdb with an insertion energy <= this value. */ dump_pdb = getenv("GMX_TPI_DUMP"); dump_ener = 0; if (dump_pdb) { sscanf(dump_pdb, "%20lf", &dump_ener); } atoms2md(top_global, inputrec, 0, NULL, top_global->natoms, mdatoms); update_mdatoms(mdatoms, inputrec->fepvals->init_lambda); snew(enerd, 1); init_enerdata(groups->grps[egcENER].nr, inputrec->fepvals->n_lambda, enerd); snew(f, top_global->natoms); /* Print to log file */ walltime_accounting_start(walltime_accounting); wallcycle_start(wcycle, ewcRUN); print_start(fplog, cr, walltime_accounting, "Test Particle Insertion"); /* The last charge group is the group to be inserted */ cg_tp = top->cgs.nr - 1; a_tp0 = top->cgs.index[cg_tp]; a_tp1 = top->cgs.index[cg_tp+1]; if (debug) { fprintf(debug, "TPI cg %d, atoms %d-%d\n", cg_tp, a_tp0, a_tp1); } GMX_RELEASE_ASSERT(inputrec->rcoulomb <= inputrec->rlist && inputrec->rvdw <= inputrec->rlist, "Twin-range interactions are not supported with TPI"); snew(x_mol, a_tp1-a_tp0); bDispCorr = (inputrec->eDispCorr != edispcNO); bCharge = FALSE; for (i = a_tp0; i < a_tp1; i++) { /* Copy the coordinates of the molecule to be insterted */ copy_rvec(state_global->x[i], x_mol[i-a_tp0]); /* Check if we need to print electrostatic energies */ bCharge |= (mdatoms->chargeA[i] != 0 || (mdatoms->chargeB && mdatoms->chargeB[i] != 0)); } bRFExcl = (bCharge && EEL_RF(fr->eeltype)); calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), state_global->x, fr->cg_cm); if (bCavity) { if (norm(fr->cg_cm[cg_tp]) > 0.5*inputrec->rlist && fplog) { fprintf(fplog, "WARNING: Your TPI molecule is not centered at 0,0,0\n"); fprintf(stderr, "WARNING: Your TPI molecule is not centered at 0,0,0\n"); } } else { /* Center the molecule to be inserted at zero */ for (i = 0; i < a_tp1-a_tp0; i++) { rvec_dec(x_mol[i], fr->cg_cm[cg_tp]); } } if (fplog) { fprintf(fplog, "\nWill insert %d atoms %s partial charges\n", a_tp1-a_tp0, bCharge ? "with" : "without"); fprintf(fplog, "\nWill insert %d times in each frame of %s\n", (int)nsteps, opt2fn("-rerun", nfile, fnm)); } if (!bCavity) { if (inputrec->nstlist > 1) { if (drmax == 0 && a_tp1-a_tp0 == 1) { gmx_fatal(FARGS, "Re-using the neighborlist %d times for insertions of a single atom in a sphere of radius %f does not make sense", inputrec->nstlist, drmax); } if (fplog) { fprintf(fplog, "Will use the same neighborlist for %d insertions in a sphere of radius %f\n", inputrec->nstlist, drmax); } } } else { if (fplog) { fprintf(fplog, "Will insert randomly in a sphere of radius %f around the center of the cavity\n", drmax); } } ngid = groups->grps[egcENER].nr; gid_tp = GET_CGINFO_GID(fr->cginfo[cg_tp]); nener = 1 + ngid; if (bDispCorr) { nener += 1; } if (bCharge) { nener += ngid; if (bRFExcl) { nener += 1; } if (EEL_FULL(fr->eeltype)) { nener += 1; } } snew(sum_UgembU, nener); /* Copy the random seed set by the user */ seed = inputrec->ld_seed; gmx::ThreeFry2x64<16> rng(seed, gmx::RandomDomain::TestParticleInsertion); // 16 bits internal counter => 2^16 * 2 = 131072 values per stream gmx::UniformRealDistribution<real> dist; if (MASTER(cr)) { fp_tpi = xvgropen(opt2fn("-tpi", nfile, fnm), "TPI energies", "Time (ps)", "(kJ mol\\S-1\\N) / (nm\\S3\\N)", oenv); xvgr_subtitle(fp_tpi, "f. are averages over one frame", oenv); snew(leg, 4+nener); e = 0; sprintf(str, "-kT log(<Ve\\S-\\betaU\\N>/<V>)"); leg[e++] = gmx_strdup(str); sprintf(str, "f. -kT log<e\\S-\\betaU\\N>"); leg[e++] = gmx_strdup(str); sprintf(str, "f. <e\\S-\\betaU\\N>"); leg[e++] = gmx_strdup(str); sprintf(str, "f. V"); leg[e++] = gmx_strdup(str); sprintf(str, "f. <Ue\\S-\\betaU\\N>"); leg[e++] = gmx_strdup(str); for (i = 0; i < ngid; i++) { sprintf(str, "f. <U\\sVdW %s\\Ne\\S-\\betaU\\N>", *(groups->grpname[groups->grps[egcENER].nm_ind[i]])); leg[e++] = gmx_strdup(str); } if (bDispCorr) { sprintf(str, "f. <U\\sdisp c\\Ne\\S-\\betaU\\N>"); leg[e++] = gmx_strdup(str); } if (bCharge) { for (i = 0; i < ngid; i++) { sprintf(str, "f. <U\\sCoul %s\\Ne\\S-\\betaU\\N>", *(groups->grpname[groups->grps[egcENER].nm_ind[i]])); leg[e++] = gmx_strdup(str); } if (bRFExcl) { sprintf(str, "f. <U\\sRF excl\\Ne\\S-\\betaU\\N>"); leg[e++] = gmx_strdup(str); } if (EEL_FULL(fr->eeltype)) { sprintf(str, "f. <U\\sCoul recip\\Ne\\S-\\betaU\\N>"); leg[e++] = gmx_strdup(str); } } xvgr_legend(fp_tpi, 4+nener, (const char**)leg, oenv); for (i = 0; i < 4+nener; i++) { sfree(leg[i]); } sfree(leg); } clear_rvec(x_init); V_all = 0; VembU_all = 0; invbinw = 10; nbin = 10; snew(bin, nbin); /* Avoid frame step numbers <= -1 */ frame_step_prev = -1; bNotLastFrame = read_first_frame(oenv, &status, opt2fn("-rerun", nfile, fnm), &rerun_fr, TRX_NEED_X); frame = 0; if (rerun_fr.natoms - (bCavity ? nat_cavity : 0) != mdatoms->nr - (a_tp1 - a_tp0)) { gmx_fatal(FARGS, "Number of atoms in trajectory (%d)%s " "is not equal the number in the run input file (%d) " "minus the number of atoms to insert (%d)\n", rerun_fr.natoms, bCavity ? " minus one" : "", mdatoms->nr, a_tp1-a_tp0); } refvolshift = log(det(rerun_fr.box)); switch (inputrec->eI) { case eiTPI: stepblocksize = inputrec->nstlist; break; case eiTPIC: stepblocksize = 1; break; default: gmx_fatal(FARGS, "Unknown integrator %s", ei_names[inputrec->eI]); } while (bNotLastFrame) { frame_step = rerun_fr.step; if (frame_step <= frame_step_prev) { /* We don't have step number in the trajectory file, * or we have constant or decreasing step numbers. * Ensure we have increasing step numbers, since we use * the step numbers as a counter for random numbers. */ frame_step = frame_step_prev + 1; } frame_step_prev = frame_step; lambda = rerun_fr.lambda; t = rerun_fr.time; sum_embU = 0; for (e = 0; e < nener; e++) { sum_UgembU[e] = 0; } /* Copy the coordinates from the input trajectory */ for (i = 0; i < rerun_fr.natoms; i++) { copy_rvec(rerun_fr.x[i], state_global->x[i]); } copy_mat(rerun_fr.box, state_global->box); V = det(state_global->box); logV = log(V); bStateChanged = TRUE; bNS = TRUE; step = cr->nodeid*stepblocksize; while (step < nsteps) { /* Restart random engine using the frame and insertion step * as counters. * Note that we need to draw several random values per iteration, * but by using the internal subcounter functionality of ThreeFry2x64 * we can draw 131072 unique 64-bit values before exhausting * the stream. This is a huge margin, and if something still goes * wrong you will get an exception when the stream is exhausted. */ rng.restart(frame_step, step); dist.reset(); // erase any memory in the distribution if (!bCavity) { /* Random insertion in the whole volume */ bNS = (step % inputrec->nstlist == 0); if (bNS) { /* Generate a random position in the box */ for (d = 0; d < DIM; d++) { x_init[d] = dist(rng)*state_global->box[d][d]; } } if (inputrec->nstlist == 1) { copy_rvec(x_init, x_tp); } else { /* Generate coordinates within |dx|=drmax of x_init */ do { for (d = 0; d < DIM; d++) { dx[d] = (2*dist(rng) - 1)*drmax; } } while (norm2(dx) > drmax*drmax); rvec_add(x_init, dx, x_tp); } } else { /* Random insertion around a cavity location * given by the last coordinate of the trajectory. */ if (step == 0) { if (nat_cavity == 1) { /* Copy the location of the cavity */ copy_rvec(rerun_fr.x[rerun_fr.natoms-1], x_init); } else { /* Determine the center of mass of the last molecule */ clear_rvec(x_init); mass_tot = 0; for (i = 0; i < nat_cavity; i++) { for (d = 0; d < DIM; d++) { x_init[d] += mass_cavity[i]*rerun_fr.x[rerun_fr.natoms-nat_cavity+i][d]; } mass_tot += mass_cavity[i]; } for (d = 0; d < DIM; d++) { x_init[d] /= mass_tot; } } } /* Generate coordinates within |dx|=drmax of x_init */ do { for (d = 0; d < DIM; d++) { dx[d] = (2*dist(rng) - 1)*drmax; } } while (norm2(dx) > drmax*drmax); rvec_add(x_init, dx, x_tp); } if (a_tp1 - a_tp0 == 1) { /* Insert a single atom, just copy the insertion location */ copy_rvec(x_tp, state_global->x[a_tp0]); } else { /* Copy the coordinates from the top file */ for (i = a_tp0; i < a_tp1; i++) { copy_rvec(x_mol[i-a_tp0], state_global->x[i]); } /* Rotate the molecule randomly */ rotate_conf(a_tp1-a_tp0, state_global->x+a_tp0, NULL, 2*M_PI*dist(rng), 2*M_PI*dist(rng), 2*M_PI*dist(rng)); /* Shift to the insertion location */ for (i = a_tp0; i < a_tp1; i++) { rvec_inc(state_global->x[i], x_tp); } } /* Clear some matrix variables */ clear_mat(force_vir); clear_mat(shake_vir); clear_mat(vir); clear_mat(pres); /* Set the charge group center of mass of the test particle */ copy_rvec(x_init, fr->cg_cm[top->cgs.nr-1]); /* Calc energy (no forces) on new positions. * Since we only need the intermolecular energy * and the RF exclusion terms of the inserted molecule occur * within a single charge group we can pass NULL for the graph. * This also avoids shifts that would move charge groups * out of the box. */ /* Make do_force do a single node force calculation */ cr->nnodes = 1; do_force(fplog, cr, inputrec, step, nrnb, wcycle, top, &top_global->groups, state_global->box, state_global->x, &state_global->hist, f, force_vir, mdatoms, enerd, fcd, state_global->lambda, NULL, fr, NULL, mu_tot, t, NULL, NULL, FALSE, GMX_FORCE_NONBONDED | GMX_FORCE_ENERGY | (bNS ? GMX_FORCE_DYNAMICBOX | GMX_FORCE_NS : 0) | (bStateChanged ? GMX_FORCE_STATECHANGED : 0)); cr->nnodes = nnodes; bStateChanged = FALSE; bNS = FALSE; /* Calculate long range corrections to pressure and energy */ calc_dispcorr(inputrec, fr, state_global->box, lambda, pres, vir, &prescorr, &enercorr, &dvdlcorr); /* figure out how to rearrange the next 4 lines MRS 8/4/2009 */ enerd->term[F_DISPCORR] = enercorr; enerd->term[F_EPOT] += enercorr; enerd->term[F_PRES] += prescorr; enerd->term[F_DVDL_VDW] += dvdlcorr; epot = enerd->term[F_EPOT]; bEnergyOutOfBounds = FALSE; /* If the compiler doesn't optimize this check away * we catch the NAN energies. * The epot>GMX_REAL_MAX check catches inf values, * which should nicely result in embU=0 through the exp below, * but it does not hurt to check anyhow. */ /* Non-bonded Interaction usually diverge at r=0. * With tabulated interaction functions the first few entries * should be capped in a consistent fashion between * repulsion, dispersion and Coulomb to avoid accidental * negative values in the total energy. * The table generation code in tables.c does this. * With user tbales the user should take care of this. */ if (epot != epot || epot > GMX_REAL_MAX) { bEnergyOutOfBounds = TRUE; } if (bEnergyOutOfBounds) { if (debug) { fprintf(debug, "\n time %.3f, step %d: non-finite energy %f, using exp(-bU)=0\n", t, (int)step, epot); } embU = 0; } else { embU = exp(-beta*epot); sum_embU += embU; /* Determine the weighted energy contributions of each energy group */ e = 0; sum_UgembU[e++] += epot*embU; if (fr->bBHAM) { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += enerd->grpp.ener[egBHAMSR][GID(i, gid_tp, ngid)]*embU; } } else { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += enerd->grpp.ener[egLJSR][GID(i, gid_tp, ngid)]*embU; } } if (bDispCorr) { sum_UgembU[e++] += enerd->term[F_DISPCORR]*embU; } if (bCharge) { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += enerd->grpp.ener[egCOULSR][GID(i, gid_tp, ngid)] * embU; } if (bRFExcl) { sum_UgembU[e++] += enerd->term[F_RF_EXCL]*embU; } if (EEL_FULL(fr->eeltype)) { sum_UgembU[e++] += enerd->term[F_COUL_RECIP]*embU; } } } if (embU == 0 || beta*epot > bU_bin_limit) { bin[0]++; } else { i = (int)((bU_logV_bin_limit - (beta*epot - logV + refvolshift))*invbinw + 0.5); if (i < 0) { i = 0; } if (i >= nbin) { realloc_bins(&bin, &nbin, i+10); } bin[i]++; } if (debug) { fprintf(debug, "TPI %7d %12.5e %12.5f %12.5f %12.5f\n", (int)step, epot, x_tp[XX], x_tp[YY], x_tp[ZZ]); } if (dump_pdb && epot <= dump_ener) { sprintf(str, "t%g_step%d.pdb", t, (int)step); sprintf(str2, "t: %f step %d ener: %f", t, (int)step, epot); write_sto_conf_mtop(str, str2, top_global, state_global->x, state_global->v, inputrec->ePBC, state_global->box); } step++; if ((step/stepblocksize) % cr->nnodes != cr->nodeid) { /* Skip all steps assigned to the other MPI ranks */ step += (cr->nnodes - 1)*stepblocksize; } } if (PAR(cr)) { /* When running in parallel sum the energies over the processes */ gmx_sumd(1, &sum_embU, cr); gmx_sumd(nener, sum_UgembU, cr); } frame++; V_all += V; VembU_all += V*sum_embU/nsteps; if (fp_tpi) { if (bVerbose || frame%10 == 0 || frame < 10) { fprintf(stderr, "mu %10.3e <mu> %10.3e\n", -log(sum_embU/nsteps)/beta, -log(VembU_all/V_all)/beta); } fprintf(fp_tpi, "%10.3f %12.5e %12.5e %12.5e %12.5e", t, VembU_all == 0 ? 20/beta : -log(VembU_all/V_all)/beta, sum_embU == 0 ? 20/beta : -log(sum_embU/nsteps)/beta, sum_embU/nsteps, V); for (e = 0; e < nener; e++) { fprintf(fp_tpi, " %12.5e", sum_UgembU[e]/nsteps); } fprintf(fp_tpi, "\n"); fflush(fp_tpi); } bNotLastFrame = read_next_frame(oenv, status, &rerun_fr); } /* End of the loop */ walltime_accounting_end(walltime_accounting); close_trj(status); if (fp_tpi != NULL) { xvgrclose(fp_tpi); } if (fplog != NULL) { fprintf(fplog, "\n"); fprintf(fplog, " <V> = %12.5e nm^3\n", V_all/frame); fprintf(fplog, " <mu> = %12.5e kJ/mol\n", -log(VembU_all/V_all)/beta); } /* Write the Boltzmann factor histogram */ if (PAR(cr)) { /* When running in parallel sum the bins over the processes */ i = nbin; global_max(cr, &i); realloc_bins(&bin, &nbin, i); gmx_sumd(nbin, bin, cr); } if (MASTER(cr)) { fp_tpi = xvgropen(opt2fn("-tpid", nfile, fnm), "TPI energy distribution", "\\betaU - log(V/<V>)", "count", oenv); sprintf(str, "number \\betaU > %g: %9.3e", bU_bin_limit, bin[0]); xvgr_subtitle(fp_tpi, str, oenv); xvgr_legend(fp_tpi, 2, (const char **)tpid_leg, oenv); for (i = nbin-1; i > 0; i--) { bUlogV = -i/invbinw + bU_logV_bin_limit - refvolshift + log(V_all/frame); fprintf(fp_tpi, "%6.2f %10d %12.5e\n", bUlogV, (int)(bin[i]+0.5), bin[i]*exp(-bUlogV)*V_all/VembU_all); } xvgrclose(fp_tpi); } sfree(bin); sfree(sum_UgembU); walltime_accounting_set_nsteps_done(walltime_accounting, frame*inputrec->nsteps); return 0; }
body_part Creature::select_body_part(Creature *source, int hit_roll) { // Get size difference (-1,0,1); int szdif = source->get_size() - get_size(); if(szdif < -1) { szdif = -1; } else if (szdif > 1) { szdif = 1; } add_msg( m_debug, "source size = %d", source->get_size() ); add_msg( m_debug, "target size = %d", get_size() ); add_msg( m_debug, "difference = %d", szdif ); std::map<body_part, double> hit_weights = default_hit_weights[szdif]; std::map<body_part, double>::iterator iter; // If the target is on the ground, even small/tiny creatures may target eyes/head. Also increases chances of larger creatures. // Any hit modifiers to locations should go here. (Tags, attack style, etc) if(is_on_ground()) { hit_weights[bp_eyes] += 10; hit_weights[bp_head] += 20; } //Adjust based on hit roll: Eyes, Head & Torso get higher, while Arms and Legs get lower. //This should eventually be replaced with targeted attacks and this being miss chances. hit_weights[bp_eyes] = floor(hit_weights[bp_eyes] * std::pow(hit_roll, 1.15) * 10); hit_weights[bp_head] = floor(hit_weights[bp_head] * std::pow(hit_roll, 1.15) * 10); hit_weights[bp_torso] = floor(hit_weights[bp_torso] * std::pow(hit_roll, 1) * 10); hit_weights[bp_arm_l] = floor(hit_weights[bp_arm_l] * std::pow(hit_roll, 0.95) * 10); hit_weights[bp_arm_r] = floor(hit_weights[bp_arm_r] * std::pow(hit_roll, 0.95) * 10); hit_weights[bp_leg_l] = floor(hit_weights[bp_leg_l] * std::pow(hit_roll, 0.975) * 10); hit_weights[bp_leg_r] = floor(hit_weights[bp_leg_r] * std::pow(hit_roll, 0.975) * 10); // Debug for seeing weights. add_msg( m_debug, "eyes = %f", hit_weights.at( bp_eyes ) ); add_msg( m_debug, "head = %f", hit_weights.at( bp_head ) ); add_msg( m_debug, "torso = %f", hit_weights.at( bp_torso ) ); add_msg( m_debug, "arm_l = %f", hit_weights.at( bp_arm_l ) ); add_msg( m_debug, "arm_r = %f", hit_weights.at( bp_arm_r ) ); add_msg( m_debug, "leg_l = %f", hit_weights.at( bp_leg_l ) ); add_msg( m_debug, "leg_r = %f", hit_weights.at( bp_leg_r ) ); double totalWeight = 0; std::set<std::pair<body_part, double>, weight_compare> adjusted_weights; for(iter = hit_weights.begin(); iter != hit_weights.end(); ++iter) { totalWeight += iter->second; adjusted_weights.insert(*iter); } body_part selected_part = bp_torso; // Blood thirsty monsters can discard body part and go to more damaged int part_rolls = 1; int repick_chance = 50; if (source->has_flag(MF_BLOODTHIRSTY)) { part_rolls += 2; if (is_player() && g->u.has_trait("ANIMALEMPATH")) { part_rolls -= 1; repick_chance -= 10; } if (is_player() && g->u.has_trait("ANIMALDISCORD")) { part_rolls += 1; repick_chance += 10; } } body_part last_part = selected_part; for(int r = 0; r < part_rolls; ++r) { double roll = rng_float(1, totalWeight); std::set<std::pair<body_part, double>, weight_compare>::iterator adj_iter; for(adj_iter = adjusted_weights.begin(); adj_iter != adjusted_weights.end(); ++adj_iter) { roll -= adj_iter->second; if(roll <= 0) { selected_part = adj_iter->first; break; } } if (r != 0) { hp_part hpart_cur = bodypart_to_hp_part(selected_part); hp_part hpart_lst = bodypart_to_hp_part(last_part); double ratio_cur = get_hp(hpart_cur) / float(get_hp_max(hpart_cur)); double ratio_lst = get_hp(hpart_lst) / float(get_hp_max(hpart_lst)); body_part cur_pick_part = selected_part; if(ratio_cur > ratio_lst && repick_chance >= rng(1,100)) selected_part = last_part; add_msg( m_debug, "picked %s from %s(%.2f)/%s(%.2f)", body_part_name(selected_part).c_str(), body_part_name(cur_pick_part).c_str(), ratio_cur, body_part_name(last_part).c_str(), ratio_lst); } last_part = selected_part; } return selected_part; }
bool monster::push_to( const tripoint &p, const int boost, const size_t depth ) { if( is_hallucination() ) { // Don't let hallucinations push, not even other hallucinations return false; } if( !has_flag( MF_PUSH_MON ) || depth > 2 || has_effect( effect_pushed ) ) { return false; } // TODO: Generalize this to Creature monster *const critter = g->critter_at<monster>( p ); if( critter == nullptr || critter == this || p == pos() ) { return false; } if( !can_move_to( p ) ) { return false; } if( critter->is_hallucination() ) { // Kill the hallu, but return false so that the regular move_to is uses instead critter->die( nullptr ); return false; } // Stability roll of the pushed critter const int defend = critter->stability_roll(); // Stability roll of the pushing zed const int attack = stability_roll() + boost; if( defend > attack ) { return false; } const int movecost_from = 50 * g->m.move_cost( p ); const int movecost_attacker = std::max( movecost_from, 200 - 10 * ( attack - defend ) ); const tripoint dir = p - pos(); // Mark self as pushed to simplify recursive pushing add_effect( effect_pushed, 1 ); for( size_t i = 0; i < 6; i++ ) { const int dx = rng( -1, 1 ); const int dy = rng( -1, 1 ); if( dx == 0 && dy == 0 ) { continue; } // Pushing forward is easier than pushing aside const int direction_penalty = abs( dx - dir.x ) + abs( dy - dir.y ); if( direction_penalty > 2 ) { continue; } tripoint dest( p.x + dx, p.y + dy, p.z ); // Pushing into cars/windows etc. is harder const int movecost_penalty = g->m.move_cost( dest ) - 2; if( movecost_penalty <= -2 ) { // Can't push into unpassable terrain continue; } int roll = attack - ( defend + direction_penalty + movecost_penalty ); if( roll < 0 ) { continue; } Creature *critter_recur = g->critter_at( dest ); if( critter_recur == nullptr || critter_recur->is_hallucination() ) { // Try to push recursively monster *mon_recur = dynamic_cast< monster * >( critter_recur ); if( mon_recur == nullptr ) { continue; } if( critter->push_to( dest, roll, depth + 1 ) ) { // The tile isn't necessarily free, need to check if( !g->critter_at( p ) ) { move_to( p ); } moves -= movecost_attacker; if( movecost_from > 100 ) { critter->add_effect( effect_downed, movecost_from / 100 + 1 ); } else { critter->moves -= movecost_from; } return true; } else { continue; } } critter_recur = g->critter_at( dest ); if( critter_recur != nullptr ) { if( critter_recur->is_hallucination() ) { critter_recur->die( nullptr ); } else { return false; } } critter->setpos( dest ); move_to( p ); moves -= movecost_attacker; if( movecost_from > 100 ) { critter->add_effect( effect_downed, movecost_from / 100 + 1 ); } else { critter->moves -= movecost_from; } return true; } // Try to trample over a much weaker zed (or one with worse rolls) // Don't allow trampling with boost if( boost > 0 || attack < 2 * defend ) { return false; } g->swap_critters( *critter, *this ); critter->add_effect( effect_stunned, rng( 0, 2 ) ); // Only print the message when near player or it can get spammy if( rl_dist( g->u.pos(), pos() ) < 4 && g->u.sees( *critter ) ) { add_msg( m_warning, _( "The %1$s tramples %2$s" ), name().c_str(), critter->disp_name().c_str() ); } moves -= movecost_attacker; if( movecost_from > 100 ) { critter->add_effect( effect_downed, movecost_from / 100 + 1 ); } else { critter->moves -= movecost_from; } return true; }
void PhotonShootingTask::Run() { // Declare local variables for _PhotonShootingTask_ MemoryArena arena; RNG rng(31 * taskNum); vector<Photon> localDirectPhotons, localIndirectPhotons, localCausticPhotons; vector<RadiancePhoton> localRadiancePhotons; u_int totalPaths = 0; bool causticDone = (integrator->nCausticPhotonsWanted == 0); bool indirectDone = (integrator->nIndirectPhotonsWanted == 0); PermutedHalton halton(6, rng); vector<Spectrum> localRpReflectances, localRpTransmittances; while (true) { // Follow photon paths for a block of samples const u_int blockSize = 4096; for (u_int i = 0; i < blockSize; ++i) { float u[6]; halton.Sample(++totalPaths, u); // Choose light to shoot photon from float lightPdf; int lightNum = lightDistribution->SampleDiscrete(u[0], &lightPdf); const Light *light = scene->lights[lightNum]; // Generate _photonRay_ from light source and initialize _alpha_ RayDifferential photonRay; float pdf; LightSample ls(u[1], u[2], u[3]); Normal Nl; Spectrum Le = light->Sample_L(scene, ls, u[4], u[5], &photonRay, &Nl, &pdf); if (pdf == 0.f || Le.IsBlack()) continue; Spectrum alpha = (AbsDot(Nl, photonRay.d) * Le) / (pdf * lightPdf); if (!alpha.IsBlack()) { // Follow photon path through scene and record intersections PBRT_PHOTON_MAP_STARTED_RAY_PATH(&photonRay, &alpha); bool specularPath = true; Intersection photonIsect; u_int nIntersections = 0; while (scene->Intersect(photonRay, &photonIsect)) { ++nIntersections; // Handle photon/surface intersection alpha *= renderer->Transmittance(scene, photonRay, NULL, arena, &rng); BSDF *photonBSDF = photonIsect.GetBSDF(photonRay, arena); BxDFType specularType = BxDFType(BSDF_REFLECTION | BSDF_TRANSMISSION | BSDF_SPECULAR); bool hasNonSpecular = (photonBSDF->NumComponents() > photonBSDF->NumComponents(specularType)); Vector wo = -photonRay.d; if (hasNonSpecular) { // Deposit photon at surface Photon photon(photonIsect.dg.p, alpha, wo); bool depositedPhoton = false; if (nIntersections == 1) { PBRT_PHOTON_MAP_DEPOSITED_DIRECT_PHOTON(&photonIsect.dg, &alpha, &wo); depositedPhoton = true; localDirectPhotons.push_back(photon); } else { // Deposit either caustic or indirect photon if (specularPath && !causticDone) { PBRT_PHOTON_MAP_DEPOSITED_CAUSTIC_PHOTON(&photonIsect.dg, &alpha, &wo); depositedPhoton = true; localCausticPhotons.push_back(photon); } else if (!specularPath && !indirectDone) { PBRT_PHOTON_MAP_DEPOSITED_INDIRECT_PHOTON(&photonIsect.dg, &alpha, &wo); depositedPhoton = true; localIndirectPhotons.push_back(photon); } } // Possibly create radiance photon at photon intersection point if (depositedPhoton && integrator->finalGather && rng.RandomFloat() < .125f) { // Store data for radiance photon Normal n = photonIsect.dg.nn; n = Faceforward(n, -photonRay.d); localRadiancePhotons.push_back(RadiancePhoton(photonIsect.dg.p, n)); // Generate random samples for computing reflectance and transmittance const int sqrtRhoSamples = 4; float rhoRSamples1[2*sqrtRhoSamples*sqrtRhoSamples]; float rhoRSamples2[2*sqrtRhoSamples*sqrtRhoSamples]; StratifiedSample2D(rhoRSamples1, sqrtRhoSamples, sqrtRhoSamples, rng); StratifiedSample2D(rhoRSamples2, sqrtRhoSamples, sqrtRhoSamples, rng); float rhoTSamples1[2*sqrtRhoSamples*sqrtRhoSamples]; float rhoTSamples2[2*sqrtRhoSamples*sqrtRhoSamples]; StratifiedSample2D(rhoTSamples1, sqrtRhoSamples, sqrtRhoSamples, rng); StratifiedSample2D(rhoTSamples2, sqrtRhoSamples, sqrtRhoSamples, rng); Spectrum rho_r = photonBSDF->rho(sqrtRhoSamples * sqrtRhoSamples, rhoRSamples1, rhoRSamples2, BSDF_ALL_REFLECTION); localRpReflectances.push_back(rho_r); Spectrum rho_t = photonBSDF->rho(sqrtRhoSamples * sqrtRhoSamples, rhoTSamples1, rhoTSamples2, BSDF_ALL_TRANSMISSION); localRpTransmittances.push_back(rho_t); } } if ((int)nIntersections >= integrator->maxPhotonDepth) break; // Sample new photon ray direction Vector wi; float pdf; BxDFType flags; Spectrum fr = photonBSDF->Sample_f(wo, &wi, BSDFSample(rng), &pdf, BSDF_ALL, &flags); if (fr.IsBlack() || pdf == 0.f) break; Spectrum anew = alpha * fr * AbsDot(wi, photonBSDF->dgShading.nn) / pdf; // Possibly terminate photon path with Russian roulette float continueProb = min(1.f, anew.y() / alpha.y()); if (rng.RandomFloat() > continueProb) break; alpha = anew / continueProb; specularPath &= ((flags & BSDF_SPECULAR) != 0); if (indirectDone && !specularPath) break; photonRay = RayDifferential(photonIsect.dg.p, wi, photonRay, photonIsect.RayEpsilon); } PBRT_PHOTON_MAP_FINISHED_RAY_PATH(&photonRay, &alpha); } arena.FreeAll(); } // Merge local photon data with data in _PhotonIntegrator_ { MutexLock lock(mutex); // Give up if we're not storing enough photons if (abortTasks) return; if (nshot > 500000 && (unsuccessful(integrator->nCausticPhotonsWanted, causticPhotons.size(), blockSize) || unsuccessful(integrator->nIndirectPhotonsWanted, indirectPhotons.size(), blockSize))) { Error("Unable to store enough photons. Giving up.\n"); abortTasks = true; return; } progress.Update(localIndirectPhotons.size() + localCausticPhotons.size()); nshot += blockSize; // Merge direct photons into shared array nDirectPaths += blockSize; for (u_int i = 0; i < localDirectPhotons.size(); ++i) directPhotons.push_back(localDirectPhotons[i]); localDirectPhotons.erase(localDirectPhotons.begin(), localDirectPhotons.end()); // Merge indirect photons into shared array if (!indirectDone) { integrator->nIndirectPaths += blockSize; for (u_int i = 0; i < localIndirectPhotons.size(); ++i) indirectPhotons.push_back(localIndirectPhotons[i]); localIndirectPhotons.erase(localIndirectPhotons.begin(), localIndirectPhotons.end()); if (indirectPhotons.size() >= integrator->nIndirectPhotonsWanted) indirectDone = true; } // Merge caustic photons into shared array if (!causticDone) { integrator->nCausticPaths += blockSize; for (u_int i = 0; i < localCausticPhotons.size(); ++i) causticPhotons.push_back(localCausticPhotons[i]); localCausticPhotons.erase(localCausticPhotons.begin(), localCausticPhotons.end()); if (causticPhotons.size() >= integrator->nCausticPhotonsWanted) causticDone = true; } // Merge radiance photons and reflectances into shared array for (u_int i = 0; i < localRadiancePhotons.size(); ++i) radiancePhotons.push_back(localRadiancePhotons[i]); localRadiancePhotons.erase(localRadiancePhotons.begin(), localRadiancePhotons.end()); for (u_int i = 0; i < localRpReflectances.size(); ++i) rpReflectances.push_back(localRpReflectances[i]); localRpReflectances.erase(localRpReflectances.begin(), localRpReflectances.end()); for (u_int i = 0; i < localRpTransmittances.size(); ++i) rpTransmittances.push_back(localRpTransmittances[i]); localRpTransmittances.erase(localRpTransmittances.begin(), localRpTransmittances.end()); } // Exit task if enough photons have been found if (indirectDone && causticDone) break; } }
void event::actualize() { switch( type ) { case EVENT_HELP: debugmsg("Currently disabled while NPC and monster factions are being rewritten."); break; case EVENT_ROBOT_ATTACK: { const auto u_pos = g->u.global_sm_location(); if (rl_dist(u_pos, map_point) <= 4) { const mtype_id& robot_type = one_in( 2 ) ? mon_copbot : mon_riotbot; g->u.add_memorial_log( pgettext("memorial_male", "Became wanted by the police!"), pgettext("memorial_female", "Became wanted by the police!")); int robx = (u_pos.x > map_point.x ? 0 - SEEX * 2 : SEEX * 4); int roby = (u_pos.y > map_point.y ? 0 - SEEY * 2 : SEEY * 4); g->summon_mon(robot_type, tripoint(robx, roby, g->u.posz())); } } break; case EVENT_SPAWN_WYRMS: { if (g->get_levz() >= 0) { return; } g->u.add_memorial_log(pgettext("memorial_male", "Drew the attention of more dark wyrms!"), pgettext("memorial_female", "Drew the attention of more dark wyrms!")); int num_wyrms = rng(1, 4); for (int i = 0; i < num_wyrms; i++) { int tries = 0; tripoint monp = g->u.pos(); do { monp.x = rng(0, SEEX * MAPSIZE); monp.y = rng(0, SEEY * MAPSIZE); tries++; } while (tries < 10 && !g->is_empty(monp) && rl_dist(g->u.pos(), monp) <= 2); if (tries < 10) { g->m.ter_set(monp, t_rock_floor); g->summon_mon(mon_dark_wyrm, monp); } } // You could drop the flag, you know. if (g->u.has_amount("petrified_eye", 1)) { sounds::sound(g->u.pos(), 60, ""); if (!g->u.is_deaf()) { add_msg(_("The eye you're carrying lets out a tortured scream!")); g->u.add_morale(MORALE_SCREAM, -15, 0, 300, 5); } } if (!one_in(25)) { // They just keep coming! g->events.add( EVENT_SPAWN_WYRMS, calendar::turn + rng( 15_turns, 25_turns ) ); } } break; case EVENT_AMIGARA: { g->u.add_memorial_log(pgettext("memorial_male", "Angered a group of amigara horrors!"), pgettext("memorial_female", "Angered a group of amigara horrors!")); int num_horrors = rng(3, 5); int faultx = -1, faulty = -1; bool horizontal = false; for (int x = 0; x < SEEX * MAPSIZE && faultx == -1; x++) { for (int y = 0; y < SEEY * MAPSIZE && faulty == -1; y++) { if (g->m.ter(x, y) == t_fault) { faultx = x; faulty = y; horizontal = (g->m.ter(x - 1, y) == t_fault || g->m.ter(x + 1, y) == t_fault); } } } for (int i = 0; i < num_horrors; i++) { int tries = 0; int monx = -1, mony = -1; do { if (horizontal) { monx = rng(faultx, faultx + 2 * SEEX - 8); for (int n = -1; n <= 1; n++) { if (g->m.ter(monx, faulty + n) == t_rock_floor) { mony = faulty + n; } } } else { // Vertical fault mony = rng(faulty, faulty + 2 * SEEY - 8); for (int n = -1; n <= 1; n++) { if (g->m.ter(faultx + n, mony) == t_rock_floor) { monx = faultx + n; } } } tries++; } while ((monx == -1 || mony == -1 || !g->is_empty({monx, mony, g->u.posz()})) && tries < 10); if (tries < 10) { g->summon_mon(mon_amigara_horror, tripoint(monx, mony, g->u.posz())); } } } break; case EVENT_ROOTS_DIE: g->u.add_memorial_log(pgettext("memorial_male", "Destroyed a triffid grove."), pgettext("memorial_female", "Destroyed a triffid grove.")); for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) { if (g->m.ter(x, y) == t_root_wall && one_in(3)) g->m.ter_set(x, y, t_underbrush); } } break; case EVENT_TEMPLE_OPEN: { g->u.add_memorial_log(pgettext("memorial_male", "Opened a strange temple."), pgettext("memorial_female", "Opened a strange temple.")); bool saw_grate = false; for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) { if (g->m.ter(x, y) == t_grate) { g->m.ter_set(x, y, t_stairs_down); if (!saw_grate && g->u.sees(tripoint(x, y,g->get_levz()))) saw_grate = true; } } } if (saw_grate) add_msg(_("The nearby grates open to reveal a staircase!")); } break; case EVENT_TEMPLE_FLOOD: { bool flooded = false; ter_id flood_buf[SEEX*MAPSIZE][SEEY*MAPSIZE]; for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) flood_buf[x][y] = g->m.ter(x, y); } for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) { if (g->m.ter(x, y) == t_water_sh) { bool deepen = false; for (int wx = x - 1; wx <= x + 1 && !deepen; wx++) { for (int wy = y - 1; wy <= y + 1 && !deepen; wy++) { if (g->m.ter(wx, wy) == t_water_dp) deepen = true; } } if (deepen) { flood_buf[x][y] = t_water_dp; flooded = true; } } else if (g->m.ter(x, y) == t_rock_floor) { bool flood = false; for (int wx = x - 1; wx <= x + 1 && !flood; wx++) { for (int wy = y - 1; wy <= y + 1 && !flood; wy++) { if (g->m.ter(wx, wy) == t_water_dp || g->m.ter(wx, wy) == t_water_sh) flood = true; } } if (flood) { flood_buf[x][y] = t_water_sh; flooded = true; } } } } if (!flooded) return; // We finished flooding the entire chamber! // Check if we should print a message if (flood_buf[g->u.posx()][g->u.posy()] != g->m.ter(g->u.posx(), g->u.posy())) { if (flood_buf[g->u.posx()][g->u.posy()] == t_water_sh) { add_msg(m_warning, _("Water quickly floods up to your knees.")); g->u.add_memorial_log(pgettext("memorial_male", "Water level reached knees."), pgettext("memorial_female", "Water level reached knees.")); } else { // Must be deep water! add_msg(m_warning, _("Water fills nearly to the ceiling!")); g->u.add_memorial_log(pgettext("memorial_male", "Water level reached the ceiling."), pgettext("memorial_female", "Water level reached the ceiling.")); g->plswim(g->u.pos()); } } // flood_buf is filled with correct tiles; now copy them back to g->m for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) g->m.ter_set(x, y, flood_buf[x][y]); } g->events.add( EVENT_TEMPLE_FLOOD, calendar::turn + rng( 2_turns, 3_turns ) ); } break; case EVENT_TEMPLE_SPAWN: { static const std::array<mtype_id, 4> temple_monsters = { { mon_sewer_snake, mon_dermatik, mon_spider_widow_giant, mon_spider_cellar_giant } }; const mtype_id &montype = random_entry( temple_monsters ); int tries = 0, x, y; do { x = rng(g->u.posx() - 5, g->u.posx() + 5); y = rng(g->u.posy() - 5, g->u.posy() + 5); tries++; } while (tries < 20 && !g->is_empty({x, y, g->u.posz()}) && rl_dist(x, y, g->u.posx(), g->u.posy()) <= 2); if (tries < 20) { g->summon_mon(montype, tripoint(x, y, g->u.posz())); } } break; default: break; // Nothing happens for other events } }
// Why put this in a Big Switch? Why not let bionics have pointers to // functions, much like monsters and items? // // Well, because like diseases, which are also in a Big Switch, bionics don't // share functions.... void player::activate_bionic(int b, game *g) { bionic bio = my_bionics[b]; int power_cost = bionics[bio.id].power_cost; if (weapon.type->id == itm_bio_claws && bio.id == bio_claws) power_cost = 0; if (power_level < power_cost) { if (my_bionics[b].powered) { g->add_msg("Your %s powers down.", bionics[bio.id].name.c_str()); my_bionics[b].powered = false; } else g->add_msg("You cannot power your %s", bionics[bio.id].name.c_str()); return; } if (my_bionics[b].powered && my_bionics[b].charge > 0) { // Already-on units just lose a bit of charge my_bionics[b].charge--; } else { // Not-on units, or those with zero charge, have to pay the power cost if (bionics[bio.id].charge_time > 0) { my_bionics[b].powered = true; my_bionics[b].charge = bionics[bio.id].charge_time; } power_level -= power_cost; } std::string junk; std::vector<point> traj; std::vector<std::string> good; std::vector<std::string> bad; WINDOW* w; int dirx, diry, t, index; InputEvent input; unsigned int l; item tmp_item; switch (bio.id) { case bio_painkiller: pkill += 6; pain -= 2; if (pkill > pain) pkill = pain; break; case bio_nanobots: healall(4); break; case bio_resonator: g->sound(posx, posy, 30, "VRRRRMP!"); for (int i = posx - 1; i <= posx + 1; i++) { for (int j = posy - 1; j <= posy + 1; j++) { g->m.bash(i, j, 40, junk); g->m.bash(i, j, 40, junk); // Multibash effect, so that doors &c will fall g->m.bash(i, j, 40, junk); if (g->m.is_destructable(i, j) && rng(1, 10) >= 4) g->m.ter(i, j) = t_rubble; } } break; case bio_time_freeze: moves += 100 * power_level; power_level = 0; g->add_msg("Your speed suddenly increases!"); if (one_in(3)) { g->add_msg("Your muscles tear with the strain."); hurt(g, bp_arms, 0, rng(5, 10)); hurt(g, bp_arms, 1, rng(5, 10)); hurt(g, bp_legs, 0, rng(7, 12)); hurt(g, bp_legs, 1, rng(7, 12)); hurt(g, bp_torso, 0, rng(5, 15)); } if (one_in(5)) add_disease(DI_TELEGLOW, rng(50, 400), g); break; case bio_teleport: g->teleport(); add_disease(DI_TELEGLOW, 300, g); break; // TODO: More stuff here (and bio_blood_filter) case bio_blood_anal: w = newwin(20, 40, 3, 10); wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); if (has_disease(DI_FUNGUS)) bad.push_back("Fungal Parasite"); if (has_disease(DI_DERMATIK)) bad.push_back("Insect Parasite"); if (has_disease(DI_POISON)) bad.push_back("Poison"); if (radiation > 0) bad.push_back("Irradiated"); if (has_disease(DI_PKILL1)) good.push_back("Minor Painkiller"); if (has_disease(DI_PKILL2)) good.push_back("Moderate Painkiller"); if (has_disease(DI_PKILL3)) good.push_back("Heavy Painkiller"); if (has_disease(DI_PKILL_L)) good.push_back("Slow-Release Painkiller"); if (has_disease(DI_DRUNK)) good.push_back("Alcohol"); if (has_disease(DI_CIG)) good.push_back("Nicotine"); if (has_disease(DI_HIGH)) good.push_back("Intoxicant: Other"); if (has_disease(DI_TOOK_PROZAC)) good.push_back("Prozac"); if (has_disease(DI_TOOK_FLUMED)) good.push_back("Antihistamines"); if (has_disease(DI_ADRENALINE)) good.push_back("Adrenaline Spike"); if (good.size() == 0 && bad.size() == 0) mvwprintz(w, 1, 1, c_white, "No effects."); else { for (int line = 1; line < 39 && line <= good.size() + bad.size(); line++) { if (line <= bad.size()) mvwprintz(w, line, 1, c_red, bad[line - 1].c_str()); else mvwprintz(w, line, 1, c_green, good[line - 1 - bad.size()].c_str()); } } wrefresh(w); refresh(); getch(); delwin(w); break; case bio_blood_filter: rem_disease(DI_FUNGUS); rem_disease(DI_POISON); rem_disease(DI_PKILL1); rem_disease(DI_PKILL2); rem_disease(DI_PKILL3); rem_disease(DI_PKILL_L); rem_disease(DI_DRUNK); rem_disease(DI_CIG); rem_disease(DI_HIGH); rem_disease(DI_TOOK_PROZAC); rem_disease(DI_TOOK_FLUMED); rem_disease(DI_ADRENALINE); break; case bio_evap: if (query_yn("Drink directly? Otherwise you will need a container.")) { tmp_item = item(g->itypes[itm_water], 0); thirst -= 50; if (has_trait(PF_GOURMAND) && thirst < -60) { g->add_msg("You can't finish it all!"); thirst = -60; } else if (!has_trait(PF_GOURMAND) && thirst < -20) { g->add_msg("You can't finish it all!"); thirst = -20; } } else { t = g->inv("Choose a container:"); if (i_at(t).type == 0) { g->add_msg("You don't have that item!"); power_level += bionics[bio_evap].power_cost; } else if (!i_at(t).is_container()) { g->add_msg("That %s isn't a container!", i_at(t).tname().c_str()); power_level += bionics[bio_evap].power_cost; } else { it_container *cont = dynamic_cast<it_container*>(i_at(t).type); if (i_at(t).volume_contained() + 1 > cont->contains) { g->add_msg("There's no space left in your %s.", i_at(t).tname().c_str()); power_level += bionics[bio_evap].power_cost; } else if (!(cont->flags & con_wtight)) { g->add_msg("Your %s isn't watertight!", i_at(t).tname().c_str()); power_level += bionics[bio_evap].power_cost; } else { g->add_msg("You pour water into your %s.", i_at(t).tname().c_str()); i_at(t).put_in(item(g->itypes[itm_water], 0)); } } } break; case bio_lighter: g->draw(); mvprintw(0, 0, "Torch in which direction?"); input = get_input(); get_direction(dirx, diry, input); if (dirx == -2) { g->add_msg("Invalid direction."); power_level += bionics[bio_lighter].power_cost; return; } dirx += posx; diry += posy; if (!g->m.add_field(g, dirx, diry, fd_fire, 1)) // Unsuccessful. g->add_msg("You can't light a fire there."); break; case bio_claws: if (weapon.type->id == itm_bio_claws) { g->add_msg("You withdraw your claws."); weapon = ret_null; } else if (weapon.type->id != 0) { g->add_msg("Your claws extend, forcing you to drop your %s.", weapon.tname().c_str()); g->m.add_item(posx, posy, weapon); weapon = item(g->itypes[itm_bio_claws], 0); weapon.invlet = '#'; } else { g->add_msg("Your claws extend!"); weapon = item(g->itypes[itm_bio_claws], 0); weapon.invlet = '#'; } break; case bio_blaster: tmp_item = weapon; weapon = item(g->itypes[itm_bio_blaster], 0); weapon.curammo = dynamic_cast<it_ammo*>(g->itypes[itm_bio_fusion]); weapon.charges = 1; g->refresh_all(); g->plfire(false); weapon = tmp_item; break; case bio_laser: tmp_item = weapon; weapon = item(g->itypes[itm_v29], 0); weapon.curammo = dynamic_cast<it_ammo*>(g->itypes[itm_laser_pack]); weapon.charges = 1; g->refresh_all(); g->plfire(false); weapon = tmp_item; break; case bio_emp: g->draw(); mvprintw(0, 0, "Fire EMP in which direction?"); input = get_input(); get_direction(dirx, diry, input); if (dirx == -2) { g->add_msg("Invalid direction."); power_level += bionics[bio_emp].power_cost; return; } dirx += posx; diry += posy; g->emp_blast(dirx, diry); break; case bio_hydraulics: g->add_msg("Your muscles hiss as hydraulic strength fills them!"); break; case bio_water_extractor: for (int i = 0; i < g->m.i_at(posx, posy).size(); i++) { item tmp = g->m.i_at(posx, posy)[i]; if (tmp.type->id == itm_corpse && query_yn("Extract water from the %s", tmp.tname().c_str())) { i = g->m.i_at(posx, posy).size() + 1; // Loop is finished t = g->inv("Choose a container:"); if (i_at(t).type == 0) { g->add_msg("You don't have that item!"); power_level += bionics[bio_water_extractor].power_cost; } else if (!i_at(t).is_container()) { g->add_msg("That %s isn't a container!", i_at(t).tname().c_str()); power_level += bionics[bio_water_extractor].power_cost; } else { it_container *cont = dynamic_cast<it_container*>(i_at(t).type); if (i_at(t).volume_contained() + 1 > cont->contains) { g->add_msg("There's no space left in your %s.", i_at(t).tname().c_str()); power_level += bionics[bio_water_extractor].power_cost; } else { g->add_msg("You pour water into your %s.", i_at(t).tname().c_str()); i_at(t).put_in(item(g->itypes[itm_water], 0)); } } } if (i == g->m.i_at(posx, posy).size() - 1) // We never chose a corpse power_level += bionics[bio_water_extractor].power_cost; } break; case bio_magnet: for (int i = posx - 10; i <= posx + 10; i++) { for (int j = posy - 10; j <= posy + 10; j++) { if (g->m.i_at(i, j).size() > 0) { if (g->m.sees(i, j, posx, posy, -1, t)) traj = line_to(i, j, posx, posy, t); else traj = line_to(i, j, posx, posy, 0); } traj.insert(traj.begin(), point(i, j)); for (int k = 0; k < g->m.i_at(i, j).size(); k++) { if (g->m.i_at(i, j)[k].made_of(IRON) || g->m.i_at(i, j)[k].made_of(STEEL)){ tmp_item = g->m.i_at(i, j)[k]; g->m.i_rem(i, j, k); for (l = 0; l < traj.size(); l++) { index = g->mon_at(traj[l].x, traj[l].y); if (index != -1) { if (g->z[index].hurt(tmp_item.weight() * 2)) g->kill_mon(index, true); g->m.add_item(traj[l].x, traj[l].y, tmp_item); l = traj.size() + 1; } else if (l > 0 && g->m.move_cost(traj[l].x, traj[l].y) == 0) { g->m.bash(traj[l].x, traj[l].y, tmp_item.weight() * 2, junk); g->sound(traj[l].x, traj[l].y, 12, junk); if (g->m.move_cost(traj[l].x, traj[l].y) == 0) { g->m.add_item(traj[l - 1].x, traj[l - 1].y, tmp_item); l = traj.size() + 1; } } } if (l == traj.size()) g->m.add_item(posx, posy, tmp_item); } } } } break; case bio_lockpick: g->draw(); mvprintw(0, 0, "Unlock in which direction?"); input = get_input(); get_direction(dirx, diry, input); if (dirx == -2) { g->add_msg("Invalid direction."); power_level += bionics[bio_lockpick].power_cost; return; } dirx += posx; diry += posy; if (g->m.ter(dirx, diry) == t_door_locked) { moves -= 40; g->add_msg("You unlock the door."); g->m.ter(dirx, diry) = t_door_c; } else g->add_msg("You can't unlock that %s.", g->m.tername(dirx, diry).c_str()); break; // Unused enums added for completeness. default: break; } }
bool player::install_bionics(game *g, it_bionic* type) { if (type == NULL) { debugmsg("Tried to install NULL bionic"); return false; } std::string bio_name = type->name.substr(5); // Strip off "CBM: " WINDOW* w = newwin(25, 80, 0, 0); int pl_skill = int_cur + skillLevel("electronics").level() * 4 + skillLevel("firstaid").level() * 3 + skillLevel("mechanics").level() * 2; int skint = int(pl_skill / 4); int skdec = int((pl_skill * 10) / 4) % 10; // Header text mvwprintz(w, 0, 0, c_white, "Installing bionics:"); mvwprintz(w, 0, 20, type->color, bio_name.c_str()); // Dividing bars for (int i = 0; i < 80; i++) { mvwputch(w, 1, i, c_ltgray, LINE_OXOX); mvwputch(w, 21, i, c_ltgray, LINE_OXOX); } // Init the list of bionics for (int i = 1; i < type->options.size(); i++) { bionic_id id = type->options[i]; mvwprintz(w, i + 2, 0, (has_bionic(id) ? c_ltred : c_ltblue), bionics[id].name.c_str()); } // Helper text mvwprintz(w, 2, 40, c_white, "Difficulty of this module: %d", type->difficulty); mvwprintz(w, 3, 40, c_white, "Your installation skill: %d.%d", skint, skdec); mvwprintz(w, 4, 40, c_white, "Installation requires high intelligence,"); mvwprintz(w, 5, 40, c_white, "and skill in electronics, first aid, and"); mvwprintz(w, 6, 40, c_white, "mechanics (in that order of importance)."); int chance_of_success = int((100 * pl_skill) / (pl_skill + 4 * type->difficulty)); mvwprintz(w, 8, 40, c_white, "Chance of success:"); nc_color col_suc; if (chance_of_success >= 95) col_suc = c_green; else if (chance_of_success >= 80) col_suc = c_ltgreen; else if (chance_of_success >= 60) col_suc = c_yellow; else if (chance_of_success >= 35) col_suc = c_ltred; else col_suc = c_red; mvwprintz(w, 8, 59, col_suc, "%d%%%%", chance_of_success); mvwprintz(w, 10, 40, c_white, "Failure may result in crippling damage,"); mvwprintz(w, 11, 40, c_white, "loss of existing bionics, genetic damage"); mvwprintz(w, 12, 40, c_white, "or faulty installation."); wrefresh(w); if (type->id == itm_bionics_battery) { // No selection list; just confirm mvwprintz(w, 2, 0, h_ltblue, "Battery Level +%d", BATTERY_AMOUNT); mvwprintz(w, 22, 0, c_ltblue, "\ Installing this bionic will increase your total battery capacity by %d.\n\ Batteries are necessary for most bionics to function. They also require a\n\ charge mechanism, which must be installed from another CBM.", BATTERY_AMOUNT); InputEvent input; wrefresh(w); do input = get_input(); while (input != Confirm && input != Close); if (input == Confirm) { practice("electronics", (100 - chance_of_success) * 1.5); practice("firstaid", (100 - chance_of_success) * 1.0); practice("mechanics", (100 - chance_of_success) * 0.5); int success = chance_of_success - rng(1, 100); if (success > 0) { g->add_msg("Successfully installed batteries."); max_power_level += BATTERY_AMOUNT; } else bionics_install_failure(g, this, success); werase(w); delwin(w); g->refresh_all(); return true; } werase(w); delwin(w); g->refresh_all(); return false; }
CheckReproducibilityBody(std::size_t GrainSize): grainSize(GrainSize) { //first generate seeds to check on, and make sure that sequence is reproducible ASSERT(SingleCheck<seedsNum>()(0),"Series generated by FastRandom must be reproducible"); std::generate(seeds,seeds+seedsNum,rng(0)); }
void mission_start::place_npc_software(mission *miss) { npc* dev = g->find_npc(miss->npc_id); if (dev == NULL) { debugmsg("Couldn't find NPC! %d", miss->npc_id); return; } g->u.i_add( item(itypes["usb_drive"], 0) ); g->add_msg(_("%s gave you a USB drive."), dev->name.c_str()); std::string type = "house"; switch (dev->myclass) { case NC_HACKER: miss->item_id = "software_hacking"; break; case NC_DOCTOR: miss->item_id = "software_medical"; type = "s_pharm"; miss->follow_up = MISSION_GET_ZOMBIE_BLOOD_ANAL; break; case NC_SCIENTIST: miss->item_id = "software_math"; break; default: miss->item_id = "software_useless"; } int dist = 0; point place; if (type == "house") { int city_id = g->cur_om->closest_city( g->om_location() ); place = g->cur_om->random_house_in_city(city_id); } else { place = g->cur_om->find_closest(g->om_location(), type, dist, false); } miss->target = place; // Make it seen on our map for (int x = place.x - 6; x <= place.x + 6; x++) { for (int y = place.y - 6; y <= place.y + 6; y++) g->cur_om->seen(x, y, 0) = true; } tinymap compmap(&(g->traps)); compmap.load(place.x * 2, place.y * 2, 0, false); point comppoint; oter_id oter = g->cur_om->ter(place.x, place.y, 0); if (oter == "house_north" || oter == "house_east" || oter == "house_south" || oter == "house_west") { std::vector<point> valid; for (int x = 0; x < SEEX * 2; x++) { for (int y = 0; y < SEEY * 2; y++) { if (compmap.ter(x, y) == t_floor && compmap.furn(x, y) == f_null) { bool okay = false; for (int x2 = x - 1; x2 <= x + 1 && !okay; x2++) { for (int y2 = y - 1; y2 <= y + 1 && !okay; y2++) { if (compmap.furn(x2, y2) == f_bed || compmap.furn(x2, y2) == f_dresser) { okay = true; valid.push_back( point(x, y) ); } } } } } } if (valid.empty()) { comppoint = point( rng(6, SEEX * 2 - 7), rng(6, SEEY * 2 - 7) ); } else { comppoint = valid[rng(0, valid.size() - 1)]; } } else if (oter == "s_pharm_north") { bool found = false; for (int x = SEEX * 2 - 1; x > 0 && !found; x--) { for (int y = SEEY * 2 - 1; y > 0 && !found; y--) { if (compmap.ter(x, y) == t_floor) { found = true; comppoint = point(x, y); } } } } else if (oter == "s_pharm_east") { bool found = false; for (int x = 0; x < SEEX * 2 && !found; x++) { for (int y = SEEY * 2 - 1; y > 0 && !found; y--) { if (compmap.ter(x, y) == t_floor) { found = true; comppoint = point(x, y); } } } } else if (oter == "s_pharm_south") { bool found = false; for (int x = 0; x < SEEX * 2 && !found; x++) { for (int y = 0; y < SEEY * 2 && !found; y++) { if (compmap.ter(x, y) == t_floor) { found = true; comppoint = point(x, y); } } } } else if (oter == "s_pharm_west") { bool found = false; for (int x = SEEX * 2 - 1; x > 0 && !found; x--) { for (int y = 0; y < SEEY * 2 && !found; y++) { if (compmap.ter(x, y) == t_floor) { found = true; comppoint = point(x, y); } } } } compmap.ter_set(comppoint.x, comppoint.y, t_console); computer *tmpcomp = compmap.add_computer(comppoint.x, comppoint.y, string_format(_("%s's Terminal"), dev->name.c_str()), 0); tmpcomp->mission_id = miss->uid; tmpcomp->add_option(_("Download Software"), COMPACT_DOWNLOAD_SOFTWARE, 0); compmap.save(g->cur_om, int(g->turn), place.x * 2, place.y * 2, 0); }
/*! * \brief For a given probability "mean" for a single %Benoulli trial, * this method returns the number of trials after which the * first success occurs. * * This method performs the \em inverse \em transformation of the * original uniformally distributed random numbers of the interval * (0,1) created by the used pseudo random number generator to * the type of the geometric distribution. * * \param mean the probability for a single %Bernoulli trial * \return the number of trials after which the first success occurs * * \author M. Kreutz * \date 1995-01-01 * * \par Changes * none * * \par Status * stable * */ long Geometric::operator( )( double mean ) { return long( ceil( log( 1 - rng( ) ) / log( 1 - mean ) ) ); }
// this function generates clothing for zombies void mdeath::zombie(game *g, monster *z) { // normal death function first mdeath::normal(g, z); // skip clothing generation if the zombie was rezzed rather than spawned if (z->no_extra_death_drops) { return; } // now generate appropriate clothing switch(z->type->id) { case mon_zombie_cop: g->m.put_items_from("cop_shoes", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); g->m.put_items_from("cop_torso", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); g->m.put_items_from("cop_pants", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); break; case mon_zombie_swimmer: if (one_in(10)) { //Wetsuit zombie g->m.put_items_from("swimmer_wetsuit", 1, z->posx, z->posy, g->turn, 0, 0, rng(1, 4)); } else { if (!one_in(4)) { g->m.put_items_from("swimmer_head", 1, z->posx, z->posy, g->turn, 0, 0, rng(1, 4)); } if (one_in(3)) { g->m.put_items_from("swimmer_torso", 1, z->posx, z->posy, g->turn, 0, 0, rng(1, 4)); } g->m.put_items_from("swimmer_pants", 1, z->posx, z->posy, g->turn, 0, 0, rng(1, 4)); if (one_in(4)) { g->m.put_items_from("swimmer_shoes", 1, z->posx, z->posy, g->turn, 0, 0, rng(1, 4)); } } break; case mon_zombie_scientist: g->m.put_items_from("lab_shoes", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); g->m.put_items_from("lab_torso", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); g->m.put_items_from("lab_pants", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); break; case mon_zombie_soldier: g->m.put_items_from("cop_shoes", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); g->m.put_items_from("mil_armor_torso", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); g->m.put_items_from("mil_armor_pants", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); if (one_in(4)) { g->m.put_items_from("mil_armor_helmet", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); } break; case mon_zombie_hulk: g->m.spawn_item(z->posx, z->posy, "rag", g->turn, 0, 0, rng(5,10)); g->m.put_items_from("pants", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); break; default: g->m.put_items_from("pants", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); g->m.put_items_from("shirts", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); if (one_in(6)) { g->m.put_items_from("jackets", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); } if (one_in(15)) { g->m.put_items_from("bags", 1, z->posx, z->posy, g->turn, 0, 0, rng(1,4)); } break; } }
// Why put this in a Big Switch? Why not let bionics have pointers to // functions, much like monsters and items? // // Well, because like diseases, which are also in a Big Switch, bionics don't // share functions.... void player::activate_bionic(int b) { bionic bio = my_bionics[b]; int power_cost = bionics[bio.id]->power_cost; if ((weapon.type->id == "bio_claws_weapon" && bio.id == "bio_claws_weapon") || (weapon.type->id == "bio_blade_weapon" && bio.id == "bio_blade_weapon")) { power_cost = 0; } if (power_level < power_cost) { if (my_bionics[b].powered) { add_msg(m_neutral, _("Your %s powers down."), bionics[bio.id]->name.c_str()); my_bionics[b].powered = false; } else { add_msg(m_info, _("You cannot power your %s"), bionics[bio.id]->name.c_str()); } return; } if (my_bionics[b].powered && my_bionics[b].charge > 0) { // Already-on units just lose a bit of charge my_bionics[b].charge--; } else { // Not-on units, or those with zero charge, have to pay the power cost if (bionics[bio.id]->charge_time > 0) { my_bionics[b].powered = true; my_bionics[b].charge = bionics[bio.id]->charge_time - 1; } power_level -= power_cost; } std::vector<point> traj; std::vector<std::string> good; std::vector<std::string> bad; int dirx, diry; item tmp_item; if(bio.id == "bio_painkiller") { pkill += 6; pain -= 2; if (pkill > pain) { pkill = pain; } } else if (bio.id == "bio_nanobots") { rem_disease("bleed"); healall(4); } else if (bio.id == "bio_night") { if (calendar::turn % 5) { add_msg(m_neutral, _("Artificial night generator active!")); } } else if (bio.id == "bio_resonator") { g->sound(posx, posy, 30, _("VRRRRMP!")); for (int i = posx - 1; i <= posx + 1; i++) { for (int j = posy - 1; j <= posy + 1; j++) { g->m.bash( i, j, 40 ); g->m.bash( i, j, 40 ); // Multibash effect, so that doors &c will fall g->m.bash( i, j, 40 ); if (g->m.is_destructable(i, j) && rng(1, 10) >= 4) { g->m.ter_set(i, j, t_rubble); } } } } else if (bio.id == "bio_time_freeze") { moves += 100 * power_level; power_level = 0; add_msg(m_good, _("Your speed suddenly increases!")); if (one_in(3)) { add_msg(m_bad, _("Your muscles tear with the strain.")); hurt(bp_arms, 0, rng(5, 10)); hurt(bp_arms, 1, rng(5, 10)); hurt(bp_legs, 0, rng(7, 12)); hurt(bp_legs, 1, rng(7, 12)); hurt(bp_torso, -1, rng(5, 15)); } if (one_in(5)) { add_disease("teleglow", rng(50, 400)); } } else if (bio.id == "bio_teleport") { g->teleport(); add_disease("teleglow", 300); } // TODO: More stuff here (and bio_blood_filter) else if(bio.id == "bio_blood_anal") { WINDOW *w = newwin(20, 40, 3 + ((TERMY > 25) ? (TERMY - 25) / 2 : 0), 10 + ((TERMX > 80) ? (TERMX - 80) / 2 : 0)); draw_border(w); if (has_disease("fungus")) { bad.push_back(_("Fungal Parasite")); } if (has_disease("dermatik")) { bad.push_back(_("Insect Parasite")); } if (has_effect("stung")) { bad.push_back(_("Stung")); } if (has_effect("poison")) { bad.push_back(_("Poison")); } if (radiation > 0) { bad.push_back(_("Irradiated")); } if (has_disease("pkill1")) { good.push_back(_("Minor Painkiller")); } if (has_disease("pkill2")) { good.push_back(_("Moderate Painkiller")); } if (has_disease("pkill3")) { good.push_back(_("Heavy Painkiller")); } if (has_disease("pkill_l")) { good.push_back(_("Slow-Release Painkiller")); } if (has_disease("drunk")) { good.push_back(_("Alcohol")); } if (has_disease("cig")) { good.push_back(_("Nicotine")); } if (has_disease("meth")) { good.push_back(_("Methamphetamines")); } if (has_disease("high")) { good.push_back(_("Intoxicant: Other")); } if (has_disease("weed_high")) { good.push_back(_("THC Intoxication")); } if (has_disease("hallu") || has_disease("visuals")) { bad.push_back(_("Magic Mushroom")); } if (has_disease("iodine")) { good.push_back(_("Iodine")); } if (has_disease("took_xanax")) { good.push_back(_("Xanax")); } if (has_disease("took_prozac")) { good.push_back(_("Prozac")); } if (has_disease("took_flumed")) { good.push_back(_("Antihistamines")); } if (has_disease("adrenaline")) { good.push_back(_("Adrenaline Spike")); } if (has_disease("tapeworm")) { // This little guy is immune to the blood filter though, as he lives in your bowels. good.push_back(_("Intestinal Parasite")); } if (has_disease("bloodworms")) { good.push_back(_("Hemolytic Parasites")); } if (has_disease("brainworm")) { // This little guy is immune to the blood filter too, as he lives in your brain. good.push_back(_("Intracranial Parasite")); } if (has_disease("paincysts")) { // These little guys are immune to the blood filter too, as they live in your muscles. good.push_back(_("Intramuscular Parasites")); } if (has_disease("tetanus")) { // Tetanus infection. good.push_back(_("Clostridium Tetani Infection")); } if (good.empty() && bad.empty()) { mvwprintz(w, 1, 1, c_white, _("No effects.")); } else { for (unsigned line = 1; line < 39 && line <= good.size() + bad.size(); line++) { if (line <= bad.size()) { mvwprintz(w, line, 1, c_red, "%s", bad[line - 1].c_str()); } else { mvwprintz(w, line, 1, c_green, "%s", good[line - 1 - bad.size()].c_str()); } } } wrefresh(w); refresh(); getch(); delwin(w); } else if(bio.id == "bio_blood_filter") { add_msg(m_neutral, _("You activate your blood filtration system.")); rem_disease("fungus"); rem_disease("dermatik"); rem_disease("bloodworms"); rem_disease("tetanus"); remove_effect("poison"); remove_effect("stung"); rem_disease("pkill1"); rem_disease("pkill2"); rem_disease("pkill3"); rem_disease("pkill_l"); rem_disease("drunk"); rem_disease("cig"); rem_disease("high"); rem_disease("hallu"); rem_disease("visuals"); rem_disease("iodine"); rem_disease("took_xanax"); rem_disease("took_prozac"); rem_disease("took_flumed"); rem_disease("adrenaline"); rem_disease("meth"); pkill = 0; stim = 0; } else if(bio.id == "bio_evap") { item water = item("water_clean", 0); if (g->handle_liquid(water, true, true)) { moves -= 100; } else if (query_yn(_("Drink from your hands?"))) { inv.push_back(water); consume(inv.position_by_type(water.typeId())); moves -= 350; } else { power_level += bionics["bio_evap"]->power_cost; } } else if(bio.id == "bio_lighter") { if(!choose_adjacent(_("Start a fire where?"), dirx, diry) || (!g->m.add_field(dirx, diry, fd_fire, 1))) { add_msg_if_player(m_info, _("You can't light a fire there.")); power_level += bionics["bio_lighter"]->power_cost; } } if(bio.id == "bio_leukocyte") { add_msg(m_neutral, _("You activate your leukocyte breeder system.")); if (health < 0) { health = 0; } else { health += 5; } } if(bio.id == "bio_geiger") { add_msg(m_info, _("Your radiation level: %d"), radiation); } if(bio.id == "bio_radscrubber") { add_msg(m_neutral, _("You activate your radiation scrubber system.")); if (radiation > 4) { radiation -= 5; } else { radiation = 0; } } if(bio.id == "bio_adrenaline") { add_msg(m_neutral, _("You activate your adrenaline pump.")); if (has_disease("adrenaline")) { add_disease("adrenaline", 50); } else { add_disease("adrenaline", 200); } } else if(bio.id == "bio_claws") { if (weapon.type->id == "bio_claws_weapon") { add_msg(m_neutral, _("You withdraw your claws.")); weapon = ret_null; } else if (weapon.has_flag ("NO_UNWIELD")) { add_msg(m_info, _("Deactivate your %s first!"), weapon.tname().c_str()); power_level += bionics[bio.id]->power_cost; return; } else if(weapon.type->id != "null") { add_msg(m_warning, _("Your claws extend, forcing you to drop your %s."), weapon.tname().c_str()); g->m.add_item_or_charges(posx, posy, weapon); weapon = item("bio_claws_weapon", 0); weapon.invlet = '#'; } else { add_msg(m_neutral, _("Your claws extend!")); weapon = item("bio_claws_weapon", 0); weapon.invlet = '#'; } } else if(bio.id == "bio_blade") { if (weapon.type->id == "bio_blade_weapon") { add_msg(m_neutral, _("You retract your blade.")); weapon = ret_null; } else if (weapon.has_flag ("NO_UNWIELD")) { add_msg(m_info, _("Deactivate your %s first!"), weapon.tname().c_str()); power_level += bionics[bio.id]->power_cost; return; } else if(weapon.type->id != "null") { add_msg(m_warning, _("Your blade extends, forcing you to drop your %s."), weapon.tname().c_str()); g->m.add_item_or_charges(posx, posy, weapon); weapon = item("bio_blade_weapon", 0); weapon.invlet = '#'; } else { add_msg(m_neutral, _("You extend your blade!")); weapon = item("bio_blade_weapon", 0); weapon.invlet = '#'; } } else if(bio.id == "bio_blaster") { tmp_item = weapon; weapon = item("bio_blaster_gun", 0); g->refresh_all(); g->plfire(false); if(weapon.charges == 1) { // not fired power_level += bionics[bio.id]->power_cost; } weapon = tmp_item; } else if (bio.id == "bio_laser") { tmp_item = weapon; weapon = item("bio_laser_gun", 0); g->refresh_all(); g->plfire(false); if(weapon.charges == 1) { // not fired power_level += bionics[bio.id]->power_cost; } weapon = tmp_item; } else if(bio.id == "bio_chain_lightning") { tmp_item = weapon; weapon = item("bio_lightning", 0); g->refresh_all(); g->plfire(false); if(weapon.charges == 1) { // not fired power_level += bionics[bio.id]->power_cost; } weapon = tmp_item; } else if (bio.id == "bio_emp") { if(choose_adjacent(_("Create an EMP where?"), dirx, diry)) { g->emp_blast(dirx, diry); } else { power_level += bionics["bio_emp"]->power_cost; } } else if (bio.id == "bio_hydraulics") { add_msg(m_good, _("Your muscles hiss as hydraulic strength fills them!")); // Sound of hissing hydraulic muscle! (not quite as loud as a car horn) g->sound(posx, posy, 19, _("HISISSS!")); } else if (bio.id == "bio_water_extractor") { bool extracted = false; for (std::vector<item>::iterator it = g->m.i_at(posx,posy).begin(); it != g->m.i_at(posx, posy).end(); ++it) { if (it->type->id == "corpse" ) { int avail = 0; if ( it->item_vars.find("remaining_water") != it->item_vars.end() ) { avail = atoi ( it->item_vars["remaining_water"].c_str() ); } else { avail = it->volume() / 2; } if(avail > 0 && query_yn(_("Extract water from the %s"), it->tname().c_str())) { item water = item("water_clean", 0); if (g->handle_liquid(water, true, true)) { moves -= 100; } else if (query_yn(_("Drink directly from the condensor?"))) { inv.push_back(water); consume(inv.position_by_type(water.typeId())); moves -= 350; } extracted = true; avail--; it->item_vars["remaining_water"] = string_format("%d", avail); break; } } } if (!extracted) { power_level += bionics["bio_water_extractor"]->power_cost; } } else if(bio.id == "bio_magnet") { for (int i = posx - 10; i <= posx + 10; i++) { for (int j = posy - 10; j <= posy + 10; j++) { if (g->m.i_at(i, j).size() > 0) { int t; //not sure why map:sees really needs this, but w/e if (g->m.sees(i, j, posx, posy, -1, t)) { traj = line_to(i, j, posx, posy, t); } else { traj = line_to(i, j, posx, posy, 0); } } traj.insert(traj.begin(), point(i, j)); for (unsigned k = 0; k < g->m.i_at(i, j).size(); k++) { if (g->m.i_at(i, j)[k].made_of("iron") || g->m.i_at(i, j)[k].made_of("steel")) { tmp_item = g->m.i_at(i, j)[k]; g->m.i_rem(i, j, k); std::vector<point>::iterator it; for (it = traj.begin(); it != traj.end(); ++it) { int index = g->mon_at(it->x, it->y); if (index != -1) { if (g->zombie(index).hurt(tmp_item.weight() / 225)) { g->kill_mon(index, true); } g->m.add_item_or_charges(it->x, it->y, tmp_item); break; } else if (it != traj.begin() && g->m.move_cost(it->x, it->y) == 0) { g->m.bash( it->x, it->y, tmp_item.weight() / 225 ); if (g->m.move_cost(it->x, it->y) == 0) { g->m.add_item_or_charges((it-1)->x, (it-1)->y, tmp_item); break; } } } if (it == traj.end()) { g->m.add_item_or_charges(posx, posy, tmp_item); } } } } } } else if(bio.id == "bio_lockpick") { if(!choose_adjacent(_("Activate your bio lockpick where?"), dirx, diry)) { power_level += bionics["bio_lockpick"]->power_cost; return; } ter_id type = g->m.ter(dirx, diry); if (type == t_door_locked || type == t_door_locked_alarm || type == t_door_locked_interior ) { moves -= 40; std::string door_name = rm_prefix(_("<door_name>door")); add_msg_if_player(m_neutral, _("With a satisfying click, the lock on the %s opens."), door_name.c_str()); g->m.ter_set(dirx, diry, t_door_c); // Locked metal doors are the Lab and Bunker entries. Those need to stay locked. } else if(type == t_door_bar_locked) { moves -= 40; std::string door_name = rm_prefix(_("<door_name>door")); add_msg_if_player(m_neutral, _("The %s swings open..."), door_name.c_str()); //Could better copy the messages from lockpick.... g->m.ter_set(dirx, diry, t_door_bar_o); } else if(type == t_chaingate_l) { moves -= 40; std::string gate_name = rm_prefix (_("<door_name>gate")); add_msg_if_player(m_neutral, _("With a satisfying click, the lock on the %s opens."), gate_name.c_str()); g->m.ter_set(dirx, diry, t_chaingate_c); } else if(type == t_door_c) { add_msg(m_info, _("That door isn't locked.")); } else { add_msg_if_player(m_neutral, _("You can't unlock that %s."), g->m.tername(dirx, diry).c_str()); } } else if(bio.id == "bio_flashbang") { add_msg_if_player(m_neutral, _("You activate your integrated flashbang generator!")); g->flashbang(posx, posy, true); } else if(bio.id == "bio_shockwave") { g->shockwave(posx, posy, 3, 4, 2, 8, true); add_msg_if_player(m_neutral, _("You unleash a powerful shockwave!")); } else if(bio.id == "bio_ups"){ add_msg_if_player(m_neutral, _("Your internal UPS powers on.")); } }
void mdeath::normal(game *g, monster *z) { if (g->u_see(z)) { g->add_msg(_("The %s dies!"), z->name().c_str()); } if(z->type->difficulty >= 15) { g->u.add_memorial_log(_("Killed a %s."), z->name().c_str()); } if (z->made_of("flesh") && z->has_flag(MF_WARM)) { g->m.add_field(g, z->posx, z->posy, fd_blood, 1); } int gib_amount = 0; bool leave_corpse = false; int corpse_damage = 0; // determine how much of a mess is left, for flesh and veggy creatures if (z->made_of("flesh") || z->made_of("veggy") || z->made_of("hflesh")) { if (z->hp >= 0 - 2 * z->type->hp) // less than 2x monster hp overkill, leave corpse { leave_corpse = true; corpse_damage = 0; } if (z->hp >= 0 - 2 * z->type->hp - 20 && z->hp < 0 - 2 * z->type->hp) // corpse with damage 1 { leave_corpse = true; corpse_damage = 1; gib_amount = rng(1,3); } if (z->hp >= 0 - 2 * z->type->hp - 40 && z->hp < 0 - 2 * z->type->hp - 20) // corpse with damage 2 { leave_corpse = true; corpse_damage = 2; gib_amount = rng(2,5); } if (z->hp >= 0 - 2 * z->type->hp - 60 && z->hp < 0 - 2 * z->type->hp - 40) // corpse with damage 3 { leave_corpse = true; corpse_damage = 3; gib_amount = rng(3,9); } if (z->hp >= 0 - 2 * z->type->hp - 80 && z->hp < 0 - 2 * z->type->hp - 60) // corpse with damage 4 { leave_corpse = true; corpse_damage = 4; gib_amount = rng(4,12); } if (z->hp <= 0 - 2 * z->type->hp - 80) // no corpse if MS_TINY or MS_SMALL, gib_amount fields only { if (z->type->size == MS_MEDIUM || z->type->size == MS_LARGE || z->type->size == MS_HUGE) { leave_corpse = true; corpse_damage = 4; } else { leave_corpse = false; } gib_amount = rng(5,15); } } // leave a corpse, if any if (leave_corpse) { item tmp; tmp.make_corpse(g->itypes["corpse"], z->type, g->turn); tmp.damage = corpse_damage; g->m.add_item_or_charges(z->posx, z->posy, tmp); } // leave gibs for (int i = 0; i < gib_amount; i++) { const int rand_posx = z->posx + rng(1,5) - 3; const int rand_posy = z->posy + rng(1,5) - 3; const int rand_density = rng(1, 3); if (z->made_of("flesh") || z->made_of("hflesh")) { g->m.add_field(g, rand_posx, rand_posy, fd_gibs_flesh, rand_density); } else if (z->made_of("veggy")) { g->m.add_field(g, rand_posx, rand_posy, fd_gibs_veggy, rand_density); } } }
bool player::uninstall_bionic(bionic_id b_id) { // malfunctioning bionics don't have associated items and get a difficulty of 12 int difficulty = 12; if( item_controller->has_template(b_id) > 0) { const it_bionic *type = dynamic_cast<it_bionic *> (item_controller->find_template(b_id)); difficulty = type->difficulty; } if (!has_bionic(b_id)) { popup(_("You don't have this bionic installed.")); return false; } if (!(inv.has_items_with_quality("CUT", 1, 1) && has_amount("1st_aid", 1))) { popup(_("Removing bionics requires a cutting tool and a first aid kit.")); return false; } if ( b_id == "bio_blaster" ) { popup(_("Removing your Fusion Blaster Arm would leave you with a useless stump.")); return false; } // removal of bionics adds +2 difficulty over installation int chance_of_success = bionic_manip_cos(int_cur, skillLevel("electronics"), skillLevel("firstaid"), skillLevel("mechanics"), difficulty + 2); if (!query_yn(_("WARNING: %i percent chance of SEVERE bodily damage! Remove anyway?"), 100 - chance_of_success)) { return false; } use_charges("1st_aid", 1); practice( "electronics", int((100 - chance_of_success) * 1.5) ); practice( "firstaid", int((100 - chance_of_success) * 1.0) ); practice( "mechanics", int((100 - chance_of_success) * 0.5) ); int success = chance_of_success - rng(1, 100); if (success > 0) { add_memorial_log(pgettext("memorial_male", "Removed bionic: %s."), pgettext("memorial_female", "Removed bionic: %s."), bionics[b_id]->name.c_str()); // until bionics can be flagged as non-removable add_msg(m_neutral, _("You jiggle your parts back into their familiar places.")); add_msg(m_good, _("Successfully removed %s."), bionics[b_id]->name.c_str()); remove_bionic(b_id); g->m.spawn_item(posx, posy, "burnt_out_bionic", 1); } else { add_memorial_log(pgettext("memorial_male", "Removed bionic: %s."), pgettext("memorial_female", "Removed bionic: %s."), bionics[b_id]->name.c_str()); bionics_uninstall_failure(this); } g->refresh_all(); return true; }
/** * Attempts to harm a creature with a projectile. * * @param source Pointer to the creature who shot the projectile. * @param missed_by Deviation of the projectile. * @param proj Reference to the projectile hitting the creature. * @param dealt_dam A reference storing the damage dealt. * @return 0 signals that the projectile should stop, * 1 signals that the projectile should not stop (i.e. dodged, passed through). */ int Creature::deal_projectile_attack(Creature *source, double missed_by, const projectile &proj, dealt_damage_instance &dealt_dam) { bool u_see_this = g->u_see(this); body_part bp_hit; // do 10,speed because speed could potentially be > 10000 if (dodge_roll() >= dice(10, proj.speed)) { if (is_player()) add_msg(_("You dodge %s projectile!"), source->disp_name(true).c_str()); else if (u_see_this) add_msg(_("%s dodges %s projectile."), disp_name().c_str(), source->disp_name(true).c_str()); return 1; } // Bounce applies whether it does damage or not. if (proj.proj_effects.count("BOUNCE")) { add_effect("bounced", 1); } double hit_value = missed_by + rng_float(-0.5, 0.5); // headshots considered elsewhere if (hit_value <= 0.4) { bp_hit = bp_torso; } else if (one_in(4)) { if( one_in(2)) { bp_hit = bp_leg_l; } else { bp_hit = bp_leg_r; } } else { if( one_in(2)) { bp_hit = bp_arm_l; } else { bp_hit = bp_arm_r; } } double monster_speed_penalty = std::max(double(get_speed()) / 80., 1.0); double goodhit = missed_by / monster_speed_penalty; double damage_mult = 1.0; std::string message = ""; game_message_type gmtSCTcolor = m_neutral; if (goodhit <= .1) { message = _("Headshot!"); source->add_msg_if_player(m_good, message.c_str()); gmtSCTcolor = m_headshot; damage_mult *= rng_float(2.45, 3.35); bp_hit = bp_head; // headshot hits the head, of course } else if (goodhit <= .2) { message = _("Critical!"); source->add_msg_if_player(m_good, message.c_str()); gmtSCTcolor = m_critical; damage_mult *= rng_float(1.75, 2.3); } else if (goodhit <= .4) { message = _("Good hit!"); source->add_msg_if_player(m_good, message.c_str()); gmtSCTcolor = m_good; damage_mult *= rng_float(1, 1.5); } else if (goodhit <= .6) { damage_mult *= rng_float(0.5, 1); } else if (goodhit <= .8) { message = _("Grazing hit."); source->add_msg_if_player(m_good, message.c_str()); gmtSCTcolor = m_grazing; damage_mult *= rng_float(0, .25); } else { damage_mult *= 0; } // copy it, since we're mutating damage_instance impact = proj.impact; if( item(proj.ammo->id, 0).has_flag("NOGIB") ) { impact.add_effect("NOGIB"); } impact.mult_damage(damage_mult); dealt_dam = deal_damage(source, bp_hit, impact); dealt_dam.bp_hit = bp_hit; // Apply ammo effects to target. const std::string target_material = get_material(); if (proj.proj_effects.count("FLAME")) { if (0 == target_material.compare("veggy") || 0 == target_material.compare("cotton") || 0 == target_material.compare("wool") || 0 == target_material.compare("paper") || 0 == target_material.compare("wood" ) ) { add_effect("onfire", rng(8, 20)); } else if (0 == target_material.compare("flesh") || 0 == target_material.compare("iflesh") ) { add_effect("onfire", rng(5, 10)); } } else if (proj.proj_effects.count("INCENDIARY") ) { if (0 == target_material.compare("veggy") || 0 == target_material.compare("cotton") || 0 == target_material.compare("wool") || 0 == target_material.compare("paper") || 0 == target_material.compare("wood") ) { add_effect("onfire", rng(2, 6)); } else if ( (0 == target_material.compare("flesh") || 0 == target_material.compare("iflesh") ) && one_in(4) ) { add_effect("onfire", rng(1, 4)); } } else if (proj.proj_effects.count("IGNITE")) { if (0 == target_material.compare("veggy") || 0 == target_material.compare("cotton") || 0 == target_material.compare("wool") || 0 == target_material.compare("paper") || 0 == target_material.compare("wood") ) { add_effect("onfire", rng(6, 6)); } else if (0 == target_material.compare("flesh") || 0 == target_material.compare("iflesh") ) { add_effect("onfire", rng(10, 10)); } } int stun_strength = 0; if (proj.proj_effects.count("BEANBAG")) { stun_strength = 4; } if(proj.proj_effects.count("WHIP")) { stun_strength = rng(4, 10); } if (proj.proj_effects.count("LARGE_BEANBAG")) { stun_strength = 16; } if( stun_strength > 0 ) { switch( get_size() ) { case MS_TINY: stun_strength *= 4; break; case MS_SMALL: stun_strength *= 2; break; case MS_MEDIUM: default: break; case MS_LARGE: stun_strength /= 2; break; case MS_HUGE: stun_strength /= 4; break; } add_effect( "stunned", rng(stun_strength / 2, stun_strength) ); } if(u_see_this) { if (damage_mult == 0) { if(source != NULL) { add_msg(source->is_player() ? _("You miss!") : _("The shot misses!")); } } else if (dealt_dam.total_damage() == 0) { add_msg(_("The shot reflects off %s %s!"), disp_name(true).c_str(), skin_name().c_str()); } else if (source != NULL) { if (source->is_player()) { //player hits monster ranged nc_color color; std::string health_bar = ""; get_HP_Bar(dealt_dam.total_damage(), this->get_hp_max(), color, health_bar, true); SCT.add(this->xpos(), this->ypos(), direction_from(0, 0, this->xpos() - source->xpos(), this->ypos() - source->ypos()), health_bar, m_good, message, gmtSCTcolor); if (this->get_hp() > 0) { get_HP_Bar(this->get_hp(), this->get_hp_max(), color, health_bar, true); SCT.add(this->xpos(), this->ypos(), direction_from(0, 0, this->xpos() - source->xpos(), this->ypos() - source->ypos()), health_bar, m_good, //~ “hit points”, used in scrolling combat text _("hp"), m_neutral, "hp"); } else { SCT.removeCreatureHP(); } add_msg(m_good, _("You hit the %s for %d damage."), disp_name().c_str(), dealt_dam.total_damage()); } else if(this->is_player()) { //monster hits player ranged //~ Hit message. 1$s is bodypart name in accusative. 2$d is damage value. add_msg_if_player(m_bad, _( "You were hit in the %1$s for %2$d damage." ), body_part_name_accusative(bp_hit).c_str( ), dealt_dam.total_damage()); } else if( u_see_this ) { add_msg(_("%s shoots %s."), source->disp_name().c_str(), disp_name().c_str()); } } } if (this->is_dead_state()) { this->die(source); } return 0; }
void bionics_install_failure(player *u, it_bionic *type, int success) { // "success" should be passed in as a negative integer representing how far off we // were for a successful install. We use this to determine consequences for failing. success = abs(success); // it would be better for code reuse just to pass in skill as an argument from install_bionic // pl_skill should be calculated the same as in install_bionics int pl_skill = u->int_cur * 4 + u->skillLevel("electronics") * 4 + u->skillLevel("firstaid") * 3 + u->skillLevel("mechanics") * 1; // for failure_level calculation, shift skill down to a float between ~0.4 - 30 float adjusted_skill = float (pl_skill) - std::min( float (40), float (pl_skill) - float (pl_skill) / float (10.0)); // failure level is decided by how far off the character was from a successful install, and // this is scaled up or down by the ratio of difficulty/skill. At high skill levels (or low // difficulties), only minor consequences occur. At low skill levels, severe consequences // are more likely. int failure_level = int(sqrt(success * 4.0 * type->difficulty / float (adjusted_skill))); int fail_type = (failure_level > 5 ? 5 : failure_level); if (fail_type <= 0) { add_msg(m_neutral, _("The installation fails without incident.")); return; } switch (rng(1, 5)) { case 1: add_msg(m_neutral, _("You flub the installation.")); break; case 2: add_msg(m_neutral, _("You mess up the installation.")); break; case 3: add_msg(m_neutral, _("The installation fails.")); break; case 4: add_msg(m_neutral, _("The installation is a failure.")); break; case 5: add_msg(m_neutral, _("You screw up the installation.")); break; } if (fail_type == 3 && u->num_bionics() == 0) { fail_type = 2; // If we have no bionics, take damage instead of losing some } switch (fail_type) { case 1: if (!(u->has_trait("NOPAIN"))) { add_msg(m_bad, _("It really hurts!")); u->mod_pain( rng(failure_level * 3, failure_level * 6) ); } break; case 2: add_msg(m_bad, _("Your body is damaged!")); u->hurtall(rng(failure_level, failure_level * 2)); break; case 3: if (u->num_bionics() <= failure_level) { add_msg(m_bad, _("All of your existing bionics are lost!")); } else { add_msg(m_bad, _("Some of your existing bionics are lost!")); } for (int i = 0; i < failure_level && u->remove_random_bionic(); i++) { ; } break; case 4: add_msg(m_mixed, _("You do damage to your genetics, causing mutation!")); while (failure_level > 0) { u->mutate(); failure_level -= rng(1, failure_level + 2); } break; case 5: { add_msg(m_bad, _("The installation is faulty!")); std::vector<bionic_id> valid; for (std::vector<std::string>::iterator it = faulty_bionics.begin() ; it != faulty_bionics.end(); ++it) { if (!u->has_bionic(*it)) { valid.push_back(*it); } } if (valid.empty()) { // We've got all the bad bionics! if (u->max_power_level > 0) { int old_power = u->max_power_level; add_msg(m_bad, _("You lose power capacity!")); u->max_power_level = rng(0, u->max_power_level - 1); g->u.add_memorial_log(pgettext("memorial_male", "Lost %d units of power capacity."), pgettext("memorial_female", "Lost %d units of power capacity."), old_power - u->max_power_level); } // TODO: What if we can't lose power capacity? No penalty? } else { int index = rng(0, valid.size() - 1); u->add_bionic(valid[index]); u->add_memorial_log(pgettext("memorial_male", "Installed bad bionic: %s."), pgettext("memorial_female", "Installed bad bionic: %s."), bionics[valid[index]]->name.c_str()); } } break; } }
void monster::plan( const mfactions &factions ) { // Bots are more intelligent than most living stuff bool smart_planning = has_flag( MF_PRIORITIZE_TARGETS ); Creature *target = nullptr; // 8.6f is rating for tank drone 60 tiles away, moose 16 or boomer 33 float dist = !smart_planning ? 1000 : 8.6f; bool fleeing = false; bool docile = friendly != 0 && has_effect( effect_docile ); bool angers_hostile_weak = type->anger.find( MTRIG_HOSTILE_WEAK ) != type->anger.end(); int angers_hostile_near = ( type->anger.find( MTRIG_HOSTILE_CLOSE ) != type->anger.end() ) ? 5 : 0; int fears_hostile_near = ( type->fear.find( MTRIG_HOSTILE_CLOSE ) != type->fear.end() ) ? 5 : 0; bool group_morale = has_flag( MF_GROUP_MORALE ) && morale < type->morale; bool swarms = has_flag( MF_SWARMS ); auto mood = attitude(); // If we can see the player, move toward them or flee, simpleminded animals are too dumb to follow the player. if( friendly == 0 && sees( g->u ) && !has_flag( MF_PET_WONT_FOLLOW ) ) { dist = rate_target( g->u, dist, smart_planning ); fleeing = fleeing || is_fleeing( g->u ); target = &g->u; if( dist <= 5 ) { anger += angers_hostile_near; morale -= fears_hostile_near; } } else if( friendly != 0 && !docile ) { // Target unfriendly monsters, only if we aren't interacting with the player. for( monster &tmp : g->all_monsters() ) { if( tmp.friendly == 0 ) { float rating = rate_target( tmp, dist, smart_planning ); if( rating < dist ) { target = &tmp; dist = rating; } } } } if( docile ) { if( friendly != 0 && target != nullptr ) { set_dest( target->pos() ); } return; } for( npc &who : g->all_npcs() ) { auto faction_att = faction.obj().attitude( who.get_monster_faction() ); if( faction_att == MFA_NEUTRAL || faction_att == MFA_FRIENDLY ) { continue; } float rating = rate_target( who, dist, smart_planning ); bool fleeing_from = is_fleeing( who ); // Switch targets if closer and hostile or scarier than current target if( ( rating < dist && fleeing ) || ( rating < dist && attitude( &who ) == MATT_ATTACK ) || ( !fleeing && fleeing_from ) ) { target = &who; dist = rating; } fleeing = fleeing || fleeing_from; if( rating <= 5 ) { anger += angers_hostile_near; morale -= fears_hostile_near; } } fleeing = fleeing || ( mood == MATT_FLEE ); if( friendly == 0 ) { for( const auto &fac : factions ) { auto faction_att = faction.obj().attitude( fac.first ); if( faction_att == MFA_NEUTRAL || faction_att == MFA_FRIENDLY ) { continue; } for( monster *const mon_ptr : fac.second ) { monster &mon = *mon_ptr; float rating = rate_target( mon, dist, smart_planning ); if( rating < dist ) { target = &mon; dist = rating; } if( rating <= 5 ) { anger += angers_hostile_near; morale -= fears_hostile_near; } } } } // Friendly monsters here // Avoid for hordes of same-faction stuff or it could get expensive const auto actual_faction = friendly == 0 ? faction : mfaction_str_id( "player" ); auto const &myfaction_iter = factions.find( actual_faction ); if( myfaction_iter == factions.end() ) { DebugLog( D_ERROR, D_GAME ) << disp_name() << " tried to find faction " << actual_faction.id().str() << " which wasn't loaded in game::monmove"; swarms = false; group_morale = false; } swarms = swarms && target == nullptr; // Only swarm if we have no target if( group_morale || swarms ) { for( monster *const mon_ptr : myfaction_iter->second ) { monster &mon = *mon_ptr; float rating = rate_target( mon, dist, smart_planning ); if( group_morale && rating <= 10 ) { morale += 10 - rating; } if( swarms ) { if( rating < 5 ) { // Too crowded here wander_pos.x = posx() * rng( 1, 3 ) - mon.posx(); wander_pos.y = posy() * rng( 1, 3 ) - mon.posy(); wandf = 2; target = nullptr; // Swarm to the furthest ally you can see } else if( rating < INT_MAX && rating > dist && wandf <= 0 ) { target = &mon; dist = rating; } } } } if( target != nullptr ) { tripoint dest = target->pos(); auto att_to_target = attitude_to( *target ); if( att_to_target == Attitude::A_HOSTILE && !fleeing ) { set_dest( dest ); } else if( fleeing ) { set_dest( tripoint( posx() * 2 - dest.x, posy() * 2 - dest.y, posz() ) ); } if( angers_hostile_weak && att_to_target != Attitude::A_FRIENDLY ) { int hp_per = target->hp_percentage(); if( hp_per <= 70 ) { anger += 10 - int( hp_per / 10 ); } } } else if( friendly > 0 && one_in( 3 ) ) { // Grow restless with no targets friendly--; } else if( friendly < 0 && sees( g->u ) ) { if( rl_dist( pos(), g->u.pos() ) > 2 ) { set_dest( g->u.pos() ); } else { unset_dest(); } } }
uint64_t randint() { return rng(); }
void trapfunc::sinkhole(int x, int y) { (void)x; (void)y; // unused g->add_msg(_("You step into a sinkhole, and start to sink down!")); g->u.add_memorial_log(pgettext("memorial_male", "Stepped into a sinkhole."), pgettext("memorial_female", "Stepped into a sinkhole.")); if (g->u.has_amount("grapnel", 1) && query_yn(_("There is a sinkhole here. Throw your grappling hook out to try to catch something?"))) { int throwroll = rng(g->u.skillLevel("throw"), g->u.skillLevel("throw") + g->u.str_cur + g->u.dex_cur); if (throwroll >= 6) { g->add_msg(_("The grappling hook catches something!")); if (rng(g->u.skillLevel("unarmed"), g->u.skillLevel("unarmed") + g->u.str_cur) > 4) { // Determine safe places for the character to get pulled to std::vector<point> safe; for (int i = g->u.posx - 1; i <= g->u.posx + 1; i++) { for (int j = g->u.posy - 1; j <= g->u.posy + 1; j++) { if (g->m.move_cost(i, j) > 0 && g->m.tr_at(i, j) != tr_pit) safe.push_back(point(i, j)); } } if (safe.empty()) { g->add_msg(_("There's nowhere to pull yourself to, and you sink!")); g->u.use_amount("grapnel", 1); g->m.spawn_item(g->u.posx + rng(-1, 1), g->u.posy + rng(-1, 1), "grapnel"); g->m.ter_set(g->u.posx, g->u.posy, t_hole); g->vertical_move(-1, true); } else { g->add_msg(_("You pull yourself to safety! The sinkhole collapses.")); int index = rng(0, safe.size() - 1); g->m.ter_set(g->u.posx, g->u.posy, t_hole); g->u.posx = safe[index].x; g->u.posy = safe[index].y; g->update_map(g->u.posx, g->u.posy); } } else { g->add_msg(_("You're not strong enough to pull yourself out...")); g->u.moves -= 100; g->u.use_amount("grapnel", 1); g->m.spawn_item(g->u.posx + rng(-1, 1), g->u.posy + rng(-1, 1), "grapnel"); g->m.ter_set(g->u.posx, g->u.posy, t_hole); g->vertical_move(-1, true); } } else { g->add_msg(_("Your throw misses completely, and you sink!")); if (one_in((g->u.str_cur + g->u.dex_cur) / 3)) { g->u.use_amount("grapnel", 1); g->m.spawn_item(g->u.posx + rng(-1, 1), g->u.posy + rng(-1, 1), "grapnel"); } g->m.ter_set(g->u.posx, g->u.posy, t_hole); g->vertical_move(-1, true); } } else if (g->u.has_amount("rope_30", 1) && query_yn(_("There is a sinkhole here. Throw your rope out to try to catch something?"))) { int throwroll = rng(g->u.skillLevel("throw"), g->u.skillLevel("throw") + g->u.str_cur + g->u.dex_cur); if (throwroll >= 12) { g->add_msg(_("The rope catches something!")); if (rng(g->u.skillLevel("unarmed"), g->u.skillLevel("unarmed") + g->u.str_cur) > 6) { // Determine safe places for the character to get pulled to std::vector<point> safe; for (int i = g->u.posx - 1; i <= g->u.posx + 1; i++) { for (int j = g->u.posy - 1; j <= g->u.posy + 1; j++) { if (g->m.move_cost(i, j) > 0 && g->m.tr_at(i, j) != tr_pit) safe.push_back(point(i, j)); } } if (safe.empty()) { g->add_msg(_("There's nowhere to pull yourself to, and you sink!")); g->u.use_amount("rope_30", 1); g->m.spawn_item(g->u.posx + rng(-1, 1), g->u.posy + rng(-1, 1), "rope_30"); g->m.ter_set(g->u.posx, g->u.posy, t_hole); g->vertical_move(-1, true); } else { g->add_msg(_("You pull yourself to safety! The sinkhole collapses.")); int index = rng(0, safe.size() - 1); g->m.ter_set(g->u.posx, g->u.posy, t_hole); g->u.posx = safe[index].x; g->u.posy = safe[index].y; g->update_map(g->u.posx, g->u.posy); } } else { g->add_msg(_("You're not strong enough to pull yourself out...")); g->u.moves -= 100; g->u.use_amount("rope_30", 1); g->m.spawn_item(g->u.posx + rng(-1, 1), g->u.posy + rng(-1, 1), "rope_30"); g->m.ter_set(g->u.posx, g->u.posy, t_hole); g->vertical_move(-1, true); } } else { g->add_msg(_("Your throw misses completely, and you sink!")); if (one_in((g->u.str_cur + g->u.dex_cur) / 3)) { g->u.use_amount("rope_30", 1); g->m.spawn_item(g->u.posx + rng(-1, 1), g->u.posy + rng(-1, 1), "rope_30"); } g->m.ter_set(g->u.posx, g->u.posy, t_hole); g->vertical_move(-1, true); } } else { g->add_msg(_("You sink into the sinkhole!")); g->m.ter_set(g->u.posx, g->u.posy, t_hole); g->vertical_move(-1, true); } }
void monster::die(game *g) { if (!dead) dead = true; // Drop goodies int total_chance = 0, total_it_chance, cur_chance, selected_location, selected_item; bool animal_done = false; std::vector<items_location_and_chance> it = g->monitems[type->id]; std::vector<itype_id> mapit; if (type->item_chance != 0 && it.size() == 0) debugmsg("Type %s has item_chance %d but no items assigned!", type->name.c_str(), type->item_chance); else { for (int i = 0; i < it.size(); i++) total_chance += it[i].chance; while (rng(0, 99) < abs(type->item_chance) && !animal_done) { cur_chance = rng(1, total_chance); selected_location = -1; while (cur_chance > 0) { selected_location++; cur_chance -= it[selected_location].chance; } total_it_chance = 0; mapit = g->mapitems[it[selected_location].loc]; for (int i = 0; i < mapit.size(); i++) total_it_chance += g->itypes[mapit[i]]->rarity; cur_chance = rng(1, total_it_chance); selected_item = -1; while (cur_chance > 0) { selected_item++; cur_chance -= g->itypes[mapit[selected_item]]->rarity; } g->m.spawn_item(posx, posy, g->itypes[mapit[selected_item]], 0); if (type->item_chance < 0) animal_done = true; // Only drop ONE item. } } // Done dropping items // If we're a queen, make nearby groups of our type start to die out if (has_flag(MF_QUEEN)) { // Do it for overmap above/below too for(int z = 0; z >= -1; --z) { std::vector<mongroup*> groups = g->cur_om.monsters_at(g->levx, g->levy, z); for (int i = 0; i < groups.size(); i++) { if (MonsterGroupManager::IsMonsterInGroup(groups[i]->type, mon_id(type->id))) groups[i]->dying = true; } } } // If we're a mission monster, update the mission if (mission_id != -1) { mission_type *misstype = g->find_mission_type(mission_id); if (misstype->goal == MGOAL_FIND_MONSTER) g->fail_mission(mission_id); if (misstype->goal == MGOAL_KILL_MONSTER) g->mission_step_complete(mission_id, 1); } // Also, perform our death function mdeath md; (md.*type->dies)(g, this); // If our species fears seeing one of our own die, process that int anger_adjust = 0, morale_adjust = 0; for (int i = 0; i < type->anger.size(); i++) { if (type->anger[i] == MTRIG_FRIEND_DIED) anger_adjust += 15; } for (int i = 0; i < type->placate.size(); i++) { if (type->placate[i] == MTRIG_FRIEND_DIED) anger_adjust -= 15; } for (int i = 0; i < type->fear.size(); i++) { if (type->fear[i] == MTRIG_FRIEND_DIED) morale_adjust -= 15; } if (anger_adjust != 0 && morale_adjust != 0) { int light = g->light_level(); for (int i = 0; i < g->z.size(); i++) { int t = 0; if (g->m.sees(g->z[i].posx, g->z[i].posy, posx, posy, light, t)) { g->z[i].morale += morale_adjust; g->z[i].anger += anger_adjust; } } } }
void defense_game::init_map(game *g) { for (int x = 0; x < OMAPX; x++) { for (int y = 0; y < OMAPY; y++) { g->cur_om.ter(x, y, 0) = ot_field; g->cur_om.seen(x, y, 0) = true; } } g->cur_om.save(); g->levx = 100; g->levy = 100; g->levz = 0; g->u.posx = SEEX; g->u.posy = SEEY; switch (location) { case DEFLOC_HOSPITAL: for (int x = 49; x <= 51; x++) { for (int y = 49; y <= 51; y++) g->cur_om.ter(x, y, 0) = ot_hospital; } g->cur_om.ter(50, 49, 0) = ot_hospital_entrance; break; case DEFLOC_MALL: for (int x = 49; x <= 51; x++) { for (int y = 49; y <= 51; y++) g->cur_om.ter(x, y, 0) = ot_megastore; } g->cur_om.ter(50, 49, 0) = ot_megastore_entrance; break; case DEFLOC_BAR: g->cur_om.ter(50, 50, 0) = ot_bar_north; break; case DEFLOC_MANSION: for (int x = 49; x <= 51; x++) { for (int y = 49; y <= 51; y++) g->cur_om.ter(x, y, 0) = ot_mansion; } g->cur_om.ter(50, 49, 0) = ot_mansion_entrance; break; } // Init the map int old_percent = 0; for (int i = 0; i <= MAPSIZE * 2; i += 2) { for (int j = 0; j <= MAPSIZE * 2; j += 2) { int mx = g->levx - MAPSIZE + i, my = g->levy - MAPSIZE + j; int percent = 100 * ((j / 2 + MAPSIZE * (i / 2))) / ((MAPSIZE) * (MAPSIZE + 1)); if (percent >= old_percent + 1) { popup_nowait("Please wait as the map generates [%s%d%]", (percent < 10 ? " " : ""), percent); old_percent = percent; } // Round down to the nearest even number mx -= mx % 2; my -= my % 2; tinymap tm(&g->itypes, &g->mapitems, &g->traps); tm.generate(g, &(g->cur_om), mx, my, 0, int(g->turn)); tm.clear_spawns(); tm.clear_traps(); tm.save(&g->cur_om, int(g->turn), mx, my, 0); } } g->m.load(g, g->levx, g->levy, g->levz, true); g->update_map(g->u.posx, g->u.posy); monster generator(g->mtypes[mon_generator], g->u.posx + 1, g->u.posy + 1); // Find a valid spot to spawn the generator std::vector<point> valid; 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 (generator.can_move_to(g->m, x, y) && g->is_empty(x, y)) valid.push_back( point(x, y) ); } } if (!valid.empty()) { point p = valid[rng(0, valid.size() - 1)]; generator.spawn(p.x, p.y); } generator.friendly = -1; g->z.push_back(generator); }
void monster::make_friendly() { plans.clear(); friendly = rng(5, 30) + rng(0, 20); }
void mission_start::place_caravan_ambush(mission *miss) { point site = target_om_ter_random("field", 1, miss, false); tinymap bay; bay.load(site.x * 2, site.y * 2, g->get_levz(), false); bay.add_vehicle("cube_van", SEEX, SEEY, 0); bay.add_vehicle("quad_bike", SEEX+6, SEEY-5, 270, 500, -1, true); bay.add_vehicle("motorcycle", SEEX-2, SEEY-9, 315, 500, -1, true); bay.add_vehicle("motorcycle", SEEX-5, SEEY-5, 90, 500, -1, true); bay.draw_square_ter(t_grass, SEEX-6, SEEY-9, SEEX+6, SEEY+3); bay.draw_square_ter(t_dirt, SEEX-4, SEEY-7, SEEX+3, SEEY+1); bay.furn_set(SEEX, SEEY-4, f_ash); bay.spawn_item(SEEX-1, SEEY-3, "rock"); bay.spawn_item(SEEX, SEEY-3, "rock"); bay.spawn_item(SEEX+1, SEEY-3, "rock"); bay.spawn_item(SEEX-1, SEEY-4, "rock"); bay.spawn_item(SEEX+1, SEEY-4, "rock"); bay.spawn_item(SEEX-1, SEEY-5, "rock"); bay.spawn_item(SEEX, SEEY-5, "rock"); bay.spawn_item(SEEX+1, SEEY-5, "rock"); bay.trap_set(SEEX+3, SEEY-5, tr_rollmat); bay.trap_set(SEEX, SEEY-7, tr_rollmat); bay.trap_set(SEEX-3, SEEY-4, tr_fur_rollmat); bay.spawn_item(SEEX+rng(-6,6), SEEY+rng(-9,3), "can_beans"); bay.spawn_item(SEEX+rng(-6,6), SEEY+rng(-9,3), "beer"); bay.spawn_item(SEEX+rng(-6,6), SEEY+rng(-9,3), "beer"); bay.spawn_item(SEEX+rng(-6,6), SEEY+rng(-9,3), "bottle_glass"); bay.spawn_item(SEEX+rng(-6,6), SEEY+rng(-9,3), "bottle_glass"); bay.spawn_item(SEEX+rng(-6,6), SEEY+rng(-9,3), "heroin"); bay.place_items("dresser", 75, SEEX-3, SEEY, SEEX-2, SEEY+2, true, 0 ); bay.place_items("softdrugs", 50, SEEX-3, SEEY, SEEX-2, SEEY+2, true, 0 ); bay.place_items("camping", 75, SEEX-3, SEEY, SEEX-2, SEEY+2, true, 0 ); bay.spawn_item(SEEX+1, SEEY+4, "9mm_casing",1,1,0,0,true); bay.spawn_item(SEEX+rng(-2,3), SEEY+rng(3,6), "9mm_casing",1,1,0,0,true); bay.spawn_item(SEEX+rng(-2,3), SEEY+rng(3,6), "9mm_casing",1,1,0,0,true); bay.spawn_item(SEEX+rng(-2,3), SEEY+rng(3,6), "9mm_casing",1,1,0,0,true); bay.add_corpse(SEEX+1, SEEY+7); bay.add_corpse(SEEX, SEEY+8); bay.add_field(SEEX, SEEY+7,fd_blood,1); bay.add_field(SEEX+2, SEEY+7,fd_blood,1); bay.add_field(SEEX-1, SEEY+8,fd_blood,1); bay.add_field(SEEX+1, SEEY+8,fd_blood,1); bay.add_field(SEEX+2, SEEY+8,fd_blood,1); bay.add_field(SEEX+1, SEEY+9,fd_blood,1); bay.add_field(SEEX, SEEY+9,fd_blood,1); bay.place_npc(SEEX+3,SEEY-5, "bandit"); bay.place_npc(SEEX, SEEY-7, "thug"); miss->target_npc_id = bay.place_npc(SEEX-3, SEEY-4, "bandit"); bay.save(); }
//////////////////////// Sector Sector::Sector(int x, int y, int z) { unsigned long _init[4] = { x, y, z, UNIVERSE_SEED }; sx = x; sy = y; sz = z; MTRand rng(_init, 4); MTRand rand(UNIVERSE_SEED); GetCustomSystems(); /* Always place random systems outside the core custom-only region */ if ((x < -CUSTOM_ONLY_RADIUS) || (x > CUSTOM_ONLY_RADIUS-1) || (y < -CUSTOM_ONLY_RADIUS) || (y > CUSTOM_ONLY_RADIUS-1) || (z < -CUSTOM_ONLY_RADIUS) || (z > CUSTOM_ONLY_RADIUS-1)) { int numSystems = (rng.Int32(4,20) * Galaxy::GetSectorDensity(x, y, z)) >> 8; for (int i=0; i<numSystems; i++) { System s; switch (rng.Int32(15)) { case 0: s.numStars = 4; break; case 1: case 2: s.numStars = 3; break; case 3: case 4: case 5: case 6: s.numStars = 2; break; default: s.numStars = 1; break; } s.p.x = rng.Double(SIZE); s.p.y = rng.Double(SIZE); s.p.z = rng.Double(SIZE); s.seed = 0; s.customSys = 0; double spec = rng.Double(1000000.0); // frequencies from wikipedia /*if (spec < 100) { // should be 1 but that is boring s.starType[0] = SBody::TYPE_STAR_O; } else if (spec < 1300) { s.starType[0] = SBody::TYPE_STAR_B; } else if (spec < 7300) { s.starType[0] = SBody::TYPE_STAR_A; } else if (spec < 37300) { s.starType[0] = SBody::TYPE_STAR_F; } else if (spec < 113300) { s.starType[0] = SBody::TYPE_STAR_G; } else if (spec < 234300) { s.starType[0] = SBody::TYPE_STAR_K; } else if (spec < 250000) { s.starType[0] = SBody::TYPE_WHITE_DWARF; } else if (spec < 900000) { s.starType[0] = SBody::TYPE_STAR_M; } else { s.starType[0] = SBody::TYPE_BROWN_DWARF; }*/ //if ((sx > 50) || (sx < -50) || // (sy > 50) || (sy < -50)) // Frequencies are low enough that we probably don't need this anymore. if (isqrt(1+sx*sx+sy*sy) > 10) { if (spec < 1) { s.starType[0] = SBody::TYPE_STAR_IM_BH; // These frequencies are made up } else if (spec < 3) { s.starType[0] = SBody::TYPE_STAR_S_BH; } else if (spec < 5) { s.starType[0] = SBody::TYPE_STAR_O_WF; } else if (spec < 8) { s.starType[0] = SBody::TYPE_STAR_B_WF; } else if (spec < 12) { s.starType[0] = SBody::TYPE_STAR_M_WF; } else if (spec < 15) { s.starType[0] = SBody::TYPE_STAR_K_HYPER_GIANT; } else if (spec < 18) { s.starType[0] = SBody::TYPE_STAR_G_HYPER_GIANT; } else if (spec < 23) { s.starType[0] = SBody::TYPE_STAR_O_HYPER_GIANT; } else if (spec < 28) { s.starType[0] = SBody::TYPE_STAR_A_HYPER_GIANT; } else if (spec < 33) { s.starType[0] = SBody::TYPE_STAR_F_HYPER_GIANT; } else if (spec < 41) { s.starType[0] = SBody::TYPE_STAR_B_HYPER_GIANT; } else if (spec < 48) { s.starType[0] = SBody::TYPE_STAR_M_HYPER_GIANT; } else if (spec < 58) { s.starType[0] = SBody::TYPE_STAR_K_SUPER_GIANT; } else if (spec < 68) { s.starType[0] = SBody::TYPE_STAR_G_SUPER_GIANT; } else if (spec < 78) { s.starType[0] = SBody::TYPE_STAR_O_SUPER_GIANT; } else if (spec < 88) { s.starType[0] = SBody::TYPE_STAR_A_SUPER_GIANT; } else if (spec < 98) { s.starType[0] = SBody::TYPE_STAR_F_SUPER_GIANT; } else if (spec < 108) { s.starType[0] = SBody::TYPE_STAR_B_SUPER_GIANT; } else if (spec < 158) { s.starType[0] = SBody::TYPE_STAR_M_SUPER_GIANT; } else if (spec < 208) { s.starType[0] = SBody::TYPE_STAR_K_GIANT; } else if (spec < 250) { s.starType[0] = SBody::TYPE_STAR_G_GIANT; } else if (spec < 300) { s.starType[0] = SBody::TYPE_STAR_O_GIANT; } else if (spec < 350) { s.starType[0] = SBody::TYPE_STAR_A_GIANT; } else if (spec < 400) { s.starType[0] = SBody::TYPE_STAR_F_GIANT; } else if (spec < 500) { s.starType[0] = SBody::TYPE_STAR_B_GIANT; } else if (spec < 700) { s.starType[0] = SBody::TYPE_STAR_M_GIANT; } else if (spec < 800) { s.starType[0] = SBody::TYPE_STAR_O; // should be 1 but that is boring } else if (spec < 2000) { // spec < 1300 / 20500 s.starType[0] = SBody::TYPE_STAR_B; } else if (spec < 8000) { // spec < 7300 s.starType[0] = SBody::TYPE_STAR_A; } else if (spec < 37300) { // spec < 37300 s.starType[0] = SBody::TYPE_STAR_F; } else if (spec < 113300) { // spec < 113300 s.starType[0] = SBody::TYPE_STAR_G; } else if (spec < 234300) { // spec < 234300 s.starType[0] = SBody::TYPE_STAR_K; } else if (spec < 250000) { // spec < 250000 s.starType[0] = SBody::TYPE_WHITE_DWARF; } else if (spec < 900000) { //spec < 900000 s.starType[0] = SBody::TYPE_STAR_M; } else { s.starType[0] = SBody::TYPE_BROWN_DWARF; } } else { if (spec < 100) { // should be 1 but that is boring s.starType[0] = SBody::TYPE_STAR_O; } else if (spec < 1300) { s.starType[0] = SBody::TYPE_STAR_B; } else if (spec < 7300) { s.starType[0] = SBody::TYPE_STAR_A; } else if (spec < 37300) { s.starType[0] = SBody::TYPE_STAR_F; } else if (spec < 113300) { s.starType[0] = SBody::TYPE_STAR_G; } else if (spec < 234300) { s.starType[0] = SBody::TYPE_STAR_K; } else if (spec < 250000) { s.starType[0] = SBody::TYPE_WHITE_DWARF; } else if (spec < 900000) { s.starType[0] = SBody::TYPE_STAR_M; } else { s.starType[0] = SBody::TYPE_BROWN_DWARF; } } //printf("%d: %d%\n", sx, sy); if (s.numStars > 1) { s.starType[1] = SBody::BodyType(rng.Int32(SBody::TYPE_STAR_MIN, s.starType[0])); if (s.numStars > 2) { s.starType[2] = SBody::BodyType(rng.Int32(SBody::TYPE_STAR_MIN, s.starType[0])); s.starType[3] = SBody::BodyType(rng.Int32(SBody::TYPE_STAR_MIN, s.starType[2])); } } if ((s.starType[0] <= SBody::TYPE_STAR_A) && (rng.Int32(10)==0)) { // make primary a giant. never more than one giant in a system // while if (isqrt(1+sx*sx+sy*sy) > 10) { if (rand.Int32(0,1000) >= 999) { s.starType[0] = SBody::TYPE_STAR_B_HYPER_GIANT; } else if (rand.Int32(0,1000) >= 998) { s.starType[0] = SBody::TYPE_STAR_O_HYPER_GIANT; } else if (rand.Int32(0,1000) >= 997) { s.starType[0] = SBody::TYPE_STAR_K_HYPER_GIANT; } else if (rand.Int32(0,1000) >= 995) { s.starType[0] = SBody::TYPE_STAR_B_SUPER_GIANT; } else if (rand.Int32(0,1000) >= 993) { s.starType[0] = SBody::TYPE_STAR_O_SUPER_GIANT; } else if (rand.Int32(0,1000) >= 990) { s.starType[0] = SBody::TYPE_STAR_K_SUPER_GIANT; } else if (rand.Int32(0,1000) >= 985) { s.starType[0] = SBody::TYPE_STAR_B_GIANT; } else if (rand.Int32(0,1000) >= 980) { s.starType[0] = SBody::TYPE_STAR_O_GIANT; } else if (rand.Int32(0,1000) >= 975) { s.starType[0] = SBody::TYPE_STAR_K_GIANT; } else if (rand.Int32(0,1000) >= 950) { s.starType[0] = SBody::TYPE_STAR_M_HYPER_GIANT; } else if (rand.Int32(0,1000) >= 875) { s.starType[0] = SBody::TYPE_STAR_M_SUPER_GIANT; } else { s.starType[0] = SBody::TYPE_STAR_M_GIANT; } } else if (isqrt(1+sx*sx+sy*sy) > 5) s.starType[0] = SBody::TYPE_STAR_M_GIANT; else s.starType[0] = SBody::TYPE_STAR_M; //printf("%d: %d%\n", sx, sy); } s.name = GenName(s, rng); //printf("%s: \n", s.name.c_str()); m_systems.push_back(s); } }
static void test_for_replica_exchange(FILE *fplog, const gmx_multisim_t *ms, struct gmx_repl_ex *re, const gmx_enerdata_t *enerd, real vol, int64_t step, real time) { int m, i, j, a, b, ap, bp, i0, i1, tmp; real delta = 0; gmx_bool bPrint, bMultiEx; gmx_bool *bEx = re->bEx; real *prob = re->prob; int *pind = re->destinations; /* permuted index */ gmx_bool bEpot = FALSE; gmx_bool bDLambda = FALSE; gmx_bool bVol = FALSE; gmx::ThreeFry2x64<64> rng(re->seed, gmx::RandomDomain::ReplicaExchange); gmx::UniformRealDistribution<real> uniformRealDist; gmx::UniformIntDistribution<int> uniformNreplDist(0, re->nrepl-1); bMultiEx = (re->nex > 1); /* multiple exchanges at each state */ fprintf(fplog, "Replica exchange at step %" PRId64 " time %.5f\n", step, time); if (re->bNPT) { for (i = 0; i < re->nrepl; i++) { re->Vol[i] = 0; } bVol = TRUE; re->Vol[re->repl] = vol; } if ((re->type == ereTEMP || re->type == ereTL)) { for (i = 0; i < re->nrepl; i++) { re->Epot[i] = 0; } bEpot = TRUE; re->Epot[re->repl] = enerd->term[F_EPOT]; /* temperatures of different states*/ for (i = 0; i < re->nrepl; i++) { re->beta[i] = 1.0/(re->q[ereTEMP][i]*BOLTZ); } } else { for (i = 0; i < re->nrepl; i++) { re->beta[i] = 1.0/(re->temp*BOLTZ); /* we have a single temperature */ } } if (re->type == ereLAMBDA || re->type == ereTL) { bDLambda = TRUE; /* lambda differences. */ /* de[i][j] is the energy of the jth simulation in the ith Hamiltonian minus the energy of the jth simulation in the jth Hamiltonian */ for (i = 0; i < re->nrepl; i++) { for (j = 0; j < re->nrepl; j++) { re->de[i][j] = 0; } } for (i = 0; i < re->nrepl; i++) { re->de[i][re->repl] = (enerd->enerpart_lambda[static_cast<int>(re->q[ereLAMBDA][i])+1]-enerd->enerpart_lambda[0]); } } /* now actually do the communication */ if (bVol) { gmx_sum_sim(re->nrepl, re->Vol, ms); } if (bEpot) { gmx_sum_sim(re->nrepl, re->Epot, ms); } if (bDLambda) { for (i = 0; i < re->nrepl; i++) { gmx_sum_sim(re->nrepl, re->de[i], ms); } } /* make a duplicate set of indices for shuffling */ for (i = 0; i < re->nrepl; i++) { pind[i] = re->ind[i]; } rng.restart( step, 0 ); if (bMultiEx) { /* multiple random switch exchange */ int nself = 0; for (i = 0; i < re->nex + nself; i++) { // For now this is superfluous, but just in case we ever add more // calls in different branches it is safer to always reset the distribution. uniformNreplDist.reset(); /* randomly select a pair */ /* in theory, could reduce this by identifying only which switches had a nonneglibible probability of occurring (log p > -100) and only operate on those switches */ /* find out which state it is from, and what label that state currently has. Likely more work that useful. */ i0 = uniformNreplDist(rng); i1 = uniformNreplDist(rng); if (i0 == i1) { nself++; continue; /* self-exchange, back up and do it again */ } a = re->ind[i0]; /* what are the indices of these states? */ b = re->ind[i1]; ap = pind[i0]; bp = pind[i1]; bPrint = FALSE; /* too noisy */ /* calculate the energy difference */ /* if the code changes to flip the STATES, rather than the configurations, use the commented version of the code */ /* delta = calc_delta(fplog,bPrint,re,a,b,ap,bp); */ delta = calc_delta(fplog, bPrint, re, ap, bp, a, b); /* we actually only use the first space in the prob and bEx array, since there are actually many switches between pairs. */ if (delta <= 0) { /* accepted */ prob[0] = 1; bEx[0] = TRUE; } else { if (delta > c_probabilityCutoff) { prob[0] = 0; } else { prob[0] = exp(-delta); } // roll a number to determine if accepted. For now it is superfluous to // reset, but just in case we ever add more calls in different branches // it is safer to always reset the distribution. uniformRealDist.reset(); bEx[0] = uniformRealDist(rng) < prob[0]; } re->prob_sum[0] += prob[0]; if (bEx[0]) { /* swap the states */ tmp = pind[i0]; pind[i0] = pind[i1]; pind[i1] = tmp; } } re->nattempt[0]++; /* keep track of total permutation trials here */ print_allswitchind(fplog, re->nrepl, pind, re->allswaps, re->tmpswap); } else { /* standard nearest neighbor replica exchange */ m = (step / re->nst) % 2; for (i = 1; i < re->nrepl; i++) { a = re->ind[i-1]; b = re->ind[i]; bPrint = (re->repl == a || re->repl == b); if (i % 2 == m) { delta = calc_delta(fplog, bPrint, re, a, b, a, b); if (delta <= 0) { /* accepted */ prob[i] = 1; bEx[i] = TRUE; } else { if (delta > c_probabilityCutoff) { prob[i] = 0; } else { prob[i] = exp(-delta); } // roll a number to determine if accepted. For now it is superfluous to // reset, but just in case we ever add more calls in different branches // it is safer to always reset the distribution. uniformRealDist.reset(); bEx[i] = uniformRealDist(rng) < prob[i]; } re->prob_sum[i] += prob[i]; if (bEx[i]) { /* swap these two */ tmp = pind[i-1]; pind[i-1] = pind[i]; pind[i] = tmp; re->nexchange[i]++; /* statistics for back compatibility */ } } else { prob[i] = -1; bEx[i] = FALSE; } } /* print some statistics */ print_ind(fplog, "ex", re->nrepl, re->ind, bEx); print_prob(fplog, "pr", re->nrepl, prob); fprintf(fplog, "\n"); re->nattempt[m]++; } /* record which moves were made and accepted */ for (i = 0; i < re->nrepl; i++) { re->nmoves[re->ind[i]][pind[i]] += 1; re->nmoves[pind[i]][re->ind[i]] += 1; } fflush(fplog); /* make sure we can see what the last exchange was */ }
void go() override { std::unique_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(get_arg("key"), rng(), get_arg("key-pass"))); if(!key) { throw CLI_Error("Failed to load key from " + get_arg("key")); } Botan::X509_Cert_Options opts; opts.common_name = get_arg("CN"); opts.country = get_arg("country"); opts.organization = get_arg("organization"); opts.email = get_arg("email"); opts.set_padding_scheme(get_arg_or("emsa", "EMSA4")); Botan::PKCS10_Request req = Botan::X509::create_cert_req(opts, *key, get_arg("hash"), rng()); output() << req.PEM_encode(); }