void CStateManagerDog::execute() { u32 state_id = u32(-1); if (!object->is_under_control()) { const CEntityAlive* enemy = object->EnemyMan.get_enemy(); if (enemy) { switch (object->EnemyMan.get_danger_type()) { case eStrong: state_id = eStatePanic; break; case eWeak: state_id = eStateAttack; break; } } else if (object->HitMemory.is_hit()) { state_id = eStateHitted; } else if (check_state(eStateHearHelpSound)) { state_id = eStateHearHelpSound; } else if (object->hear_interesting_sound) { state_id = eStateHearInterestingSound; } else if (object->hear_dangerous_sound) { state_id = eStateHearDangerousSound; } else { if (can_eat()) state_id = eStateEat; else state_id = eStateRest; } } else state_id = eStateControlled; select_state (state_id); // выполнить текущее состояние get_state_current()->execute(); prev_substate = current_substate; }
void CStateManagerZombie::execute() { if (object->com_man().ta_is_active()) return; u32 state_id = u32(-1); if (!object->is_under_control()) { const CEntityAlive* enemy = object->EnemyMan.get_enemy(); if (enemy) { state_id = eStateAttack; } else if (check_state(eStateHearHelpSound)) { state_id = eStateHearHelpSound; } else if (object->hear_interesting_sound || object->hear_dangerous_sound) { state_id = eStateHearInterestingSound; } else { if (can_eat()) state_id = eStateEat; else state_id = eStateRest; } } else state_id = eStateControlled; // установить текущее состояние select_state(state_id); // выполнить текущее состояние get_state_current()->execute(); prev_substate = current_substate; }
void CStateManagerFracture::execute() { u32 state_id = u32(-1); const CEntityAlive* enemy = object->EnemyMan.get_enemy(); if (enemy) { switch (object->EnemyMan.get_danger_type()) { case eStrong: state_id = eStatePanic; break; case eWeak: state_id = eStateAttack; break; } } else if (object->HitMemory.is_hit()) { state_id = eStateHitted; } else if (object->hear_interesting_sound || object->hear_dangerous_sound) { state_id = eStateHearDangerousSound; } else { if (can_eat()) state_id = eStateEat; else { // Rest & Idle states here state_id = eStateRest; } } // установить текущее состояние select_state(state_id); // выполнить текущее состояние get_state_current()->execute(); prev_substate = current_substate; }
byte anyone_can_eat(chip color) { for (byte y=0; y<8; y++) for (byte x=0; x<8; x++) if (can_eat(x, y, color)) return 1; return 0; }
byte do_step(byte x, byte y, chip color) { if (can_eat(selected_x, selected_y, color)) { if (do_eat(x, y, color)) return 2; // 2 - ход закончился рубкой. return 0; } return do_move(x, y, color); }
bool player::can_feed_battery_with( const item &it ) const { if( !it.is_ammo() || can_eat( it ).success() || !has_active_bionic( bio_batteries ) ) { return false; } return it.type->ammo->type.count( ammotype( "battery" ) ); }
int find_ENERGY() { int ans_ENERGY=-1,ans_ADVANCED_ENERGY=-1,sum=0; double dis=10000000,r=status->objects[0].radius; for (int i=0;i<map->objects_number;++i) { if (map->objects[i].type==ENERGY) { ++sum; if (ans_ADVANCED_ENERGY!=-1) continue; if (!can_eat(map->objects[i].pos,r)) continue; double temp=Distance(map->objects[i].pos,status->objects[0].pos); if (temp<dis) { dis=temp; ans_ENERGY=i; }; continue; }; if (map->objects[i].type==ADVANCED_ENERGY) { //printf("AI3 find a ADVANCED_ENERGY\n"); if (!can_eat(map->objects[i].pos,r)) continue; if (ans_ADVANCED_ENERGY==-1) { ans_ADVANCED_ENERGY=i; dis=Distance(map->objects[i].pos,status->objects[0].pos); continue; }; double temp=Distance(map->objects[i].pos,status->objects[0].pos); if (temp<dis) { dis=temp; ans_ADVANCED_ENERGY=i; }; }; }; printf("AI3 find %d energy\n",sum); printf("There are %d object\n",map->objects_number); if (ans_ADVANCED_ENERGY!=-1) return ans_ADVANCED_ENERGY; else return ans_ENERGY; };
void his_step() { chip damka; if (HisColor == White) damka = WDamka; else damka = BDamka; click_x = hishod[3 + 2*hishod_part] - 65; click_y = hishod[4 + 2*hishod_part] - 49; hishod_part++; if (board[click_y][click_x] == None) { byte step_status = do_step(click_x, click_y, HisColor); if (step_status > 0) { apply_select(selected_x, selected_y, 0); chip old_chip = board[selected_y][selected_x]; board[selected_y][selected_x] = None; apply_color(selected_x, selected_y); board[click_y][click_x] = old_chip; if (step_status == 2 && can_eat(click_x, click_y, HisColor)) { // 2 - возможен повторный ход, т.к. предыдущий был рубкой. apply_color(click_x, click_y); apply_select(click_x, click_y, 1); if ((HisColor == White && click_y == 7) || (HisColor == Black && click_y == 0)) futureDamka = 1; if (hishod_part < hishod_len) { his_step(); } else { debug_print("his_step error4", 15, 6); error(); } } else { if (futureDamka || (HisColor == White && click_y == 7) || (HisColor == Black && click_y == 0)) board[click_y][click_x] = damka; apply_color(click_x, click_y); forbidden_direction = DNone; if (hishod_part == hishod_len) { if (game_over()) { ggs = GGNEW; } else { if (HisColor == White) ggs = GGStartStepBlack; else ggs = GGStartStepWhite; } Mouse_Clc_Restart(); } else { debug_print("his_step error3", 15, 6); error(); } } } else { debug_print("his_step error2", 15, 6); error(); } } else { debug_print("his_step error1", 15, 6); error(); } }
bool player::can_feed_furnace_with( const item &it ) const { if( !it.flammable() || it.has_flag( "RADIOACTIVE" ) || can_eat( it ).success() ) { return false; } if( !has_active_bionic( bio_furnace ) ) { return false; } return it.typeId() != "corpse"; // @todo Eliminate the hard-coded special case. }
void wait_for_meal_and_eat(ThreadData *_data) { ThreadData data = (*(ThreadData*)_data); do { if (can_eat(data)) { eat(_data); break; } else { pthread_cond_wait(&data.cond[EATING_COND], &data.cup_m[CUCUMBER]); } } while (1); }
hint_rating player::rate_action_eat( const item &it ) const { if( !it.is_food_container( this ) && !it.is_food( this ) ) { return HINT_CANT; } const auto rating = can_eat( it ); if( rating == EDIBLE ) { return HINT_GOOD; } else if( rating == INEDIBLE || rating == INEDIBLE_MUTATION ) { return HINT_CANT; } return HINT_IFFY; }
bool player::can_feed_reactor_with( const item &it ) const { static const std::set<ammotype> acceptable = {{ ammotype( "reactor_slurry" ), ammotype( "plutonium" ) } }; if( !it.is_ammo() || can_eat( it ).success() ) { return false; } if( !has_active_bionic( bio_reactor ) && !has_active_bionic( bio_advreactor ) ) { return false; } return std::any_of( acceptable.begin(), acceptable.end(), [ &it ]( const ammotype & elem ) { return it.type->ammo->type.count( elem ); } ); }
void step(chip color) { chip damka; if (color == White) damka = WDamka; else damka = BDamka; if (mc == MCBoard) { if (board[click_y][click_x] == None) { byte step_status = do_step(click_x, click_y, color); if (step_status > 0) { write_hod(click_x, click_y); apply_select(selected_x, selected_y, 0); chip old_chip = board[selected_y][selected_x]; board[selected_y][selected_x] = None; apply_color(selected_x, selected_y); board[click_y][click_x] = old_chip; if (step_status == 2 && can_eat(click_x, click_y, color)) { // 2 - возможен повторный ход, т.к. предыдущий был рубкой. apply_color(click_x, click_y); apply_select(click_x, click_y, 1); if ((color == White && click_y == 7) || (color == Black && click_y == 0)) futureDamka = 1; } else { if (futureDamka || (color == White && click_y == 7) || (color == Black && click_y == 0)) board[click_y][click_x] = damka; apply_color(click_x, click_y); formalize_hod(); debug_print(myhod, 3 + 2*myhod_len, Dmy); send_str(myhod, 3 + 2*myhod_len); forbidden_direction = DNone; if (game_over()) { ggs = GGNEW; } else { if (color == White) ggs = GGStartStepBlack; else ggs = GGStartStepWhite; } } } } } }
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 CStateManagerBloodsucker::execute () { u32 state_id = u32(-1); const CEntityAlive* enemy = object->EnemyMan.get_enemy(); if ( !object->is_drag_anim_jump() && !object->is_animated() ) { if ( enemy ) { if ( check_state(eStateCustom_Vampire) ) { state_id = eStateCustom_Vampire; } else { switch ( object->EnemyMan.get_danger_type() ) { case eStrong: state_id = eStatePanic; break; case eWeak: state_id = eStateAttack; break; } } } else if ( object->HitMemory.is_hit() ) { state_id = eStateHitted; } else if ( object->hear_interesting_sound ) { state_id = eStateHearInterestingSound; } else { if ( can_eat() ) state_id = eStateEat; else state_id = eStateRest; } /////////////////////////////////////////////////////////////////////////////// // Additional /////////////////////////////////////////////////////////////////////////////// // check if start interesting sound state // if ( (prev_substate != eStateHearInterestingSound) && (state_id == eStateHearInterestingSound) ) // { // object->start_invisible_predator(); // } // else // // check if stop interesting sound state // if ( (prev_substate == eStateHearInterestingSound) && (state_id != eStateHearInterestingSound) ) // { // object->stop_invisible_predator(); // } select_state(state_id); // выполнить текущее состояние get_state_current()->execute(); prev_substate = current_substate; } else { state_id = eStateCustom; if ( object->is_drag_anim_jump() ) { select_state(state_id); // выполнить текущее состояние get_state_current()->execute(); prev_substate = current_substate; drag_object(); } } }
void get_command() { isNewCommand = 0; while (1) { byte c; Get_Chr(); asm jc no_char asm mov c, al if (argslen == 2 || (argslen == 1 && c != 'S')) debug_print(&c, 1, 8); timer55 = 0; get_automat(c); if (getst == GETSTART || getst == GETERR) { isNewCommand = 1; goto no_char; } } no_char: } void get_automat(byte c) { if (getst == GETNEXT) getst = GETSTART; switch (getst) { case GETSTART: { switch (c) { case 'S': getst = GETS; break; case 'C': getst = GETC; break; case 'N': getst = GETN; break; case 'D': getst = GETD; break; case 'F': getst = GETF; break; case 'E': getst = GETE; break; case 'L': case 'M': getst = GETLM;break; case 'X': getst = GETX; break; default: getst = GETERR; } break; } case GETS: { if (c == 'S') { if (argslen >= 2) debug_print("SS", 2, Dhis); getst = GETNEXT; } else { getst = GETERR; } break; } case GETC: { if (c == '0') { debug_print("C0", 2, Dhis); comm = COMC0; getst = GETSTART; } else if (c >= '1' && c <= '3') { STR[0] = 'C'; STR[1] = c; debug_print(STR, 2, Dhis); comm = COMCx; Cx = c - 49; getst = GETSTART; } else { getst = GETERR; } break; } case GETN: { if (c == 'G') { debug_print("NG", 2, Dhis); comm = COMNG; getst = GETSTART; } else { getst = GETERR; } break; } case GETD: { switch (c) { case '0': { debug_print("D0", 2, Dhis); comm = COMD0; getst = GETSTART; break; } case '2': { debug_print("D2", 2, Dhis); comm = COMD2; getst = GETSTART; break; } case '3': { debug_print("D3", 2, Dhis); comm = COMD3; getst = GETSTART; break; } default: { if (c >= '4' && c <= '9') { STR[0] = 'D'; STR[1] = c; debug_print(STR, 2, Dhis); getst = GETNEXT; } else { getst = GETERR; } } } break; } case GETF: { if (c == 'F') { debug_print("FF", 2, Dhis); comm = COMFF; getst = GETSTART; } else { getst = GETERR; } break; } case GETE: { if (c == 'X') { debug_print("EX", 2, Dhis); comm = COMEX; getst = GETSTART; } else { getst = GETERR; } break; } case GETLM: { if (c == '$') { debug_print("ML$", 3, Dhis); getst = GETNEXT; } break; } case GETX: { if (c == '0' || c == '1') { hishod_len = c - 48; getst = GETXX; } else { getst = GETERR; } break; } case GETXX: { if (c >= '0' && c <= '9') { hishod_len = hishod_len*10 + (c - 48); templen = 0; getst = GETLEN; } else { getst = GETERR; } break; } case GETLEN: { hishod[templen+3] = c; templen++; if (templen >= hishod_len*2) { hishod[0] = 'X'; hishod[1] = hishod_len / 10 + 48; hishod[2] = hishod_len % 10 + 48; debug_print(hishod, 3+hishod_len*2, Dhis); comm = COMX; getst = GETSTART; } break; } default: { getst = GETERR; } } } mouse_click_status get_click() { int x, y; int y_step = 28*2; Mouse_Clc(); asm { jnc no_clc; mov x, ax mov y, bx; } goto clc; no_clc: return MCNone; clc: if (x < 345 && y < 345) { x = x / 43; y = y / 43; if (MyColor == White) { click_x = x; click_y = 7-y; } else { click_x = 7-x; click_y = y; } return MCBoard; } if (x > 356 && x < 377) { if (y > 54 && y < 100) return MCNG; if (y > 54+y_step && y < 100+y_step) return MCD2; if (y > 54+y_step*2 && y < 100+y_step*2) return MCD3; if (y > 54+y_step*3 && y < 100+y_step*3) return MCFF; } return MCNone; } byte can_step(byte x, byte y, chip color) { if (can_eat(x, y, color)) return 1; if (can_move(x, y, color)) { if (!anyone_can_eat(color)) { return 1; } } return 0; } byte can_eat(byte x, byte y, chip color) { byte cell = board[y][x]; if (color == White) { if (cell == White) { if (y<6 && board[y+2][x] == None && (board[y+1][x] == Black || board[y+1][x] == BDamka)) return 1; if (x>1 && board[y][x-2] == None && (board[y][x-1] == Black || board[y][x-1] == BDamka)) return 1; if (x<6 && board[y][x+2] == None && (board[y][x+1] == Black || board[y][x+1] == BDamka)) return 1; } else if (cell == WDamka) { return damka_can_eat(x, y, color); } } else { if (cell == Black) { if (y>1 && board[y-2][x] == None && (board[y-1][x] == White || board[y-1][x] == WDamka)) return 1; if (x>1 && board[y][x-2] == None && (board[y][x-1] == White || board[y][x-1] == WDamka)) return 1; if (x<6 && board[y][x+2] == None && (board[y][x+1] == White || board[y][x+1] == WDamka)) return 1; } else if (cell == BDamka) { return damka_can_eat(x, y, color); } } return 0; }
ret_val<edible_rating> player::will_eat( const item &food, bool interactive ) const { const auto ret = can_eat( food ); if( !ret.success() ) { if( interactive ) { add_msg_if_player( m_info, "%s", ret.c_str() ); } return ret; } std::vector<ret_val<edible_rating>> consequences; const auto add_consequence = [&consequences]( const std::string & msg, edible_rating code ) { consequences.emplace_back( ret_val<edible_rating>::make_failure( code, msg ) ); }; const bool saprophage = has_trait( trait_id( "SAPROPHAGE" ) ); const auto &comest = food.type->comestible; if( food.rotten() ) { const bool saprovore = has_trait( trait_id( "SAPROVORE" ) ); if( !saprophage && !saprovore ) { add_consequence( _( "This is rotten and smells awful!" ), ROTTEN ); } } const bool carnivore = has_trait( trait_id( "CARNIVORE" ) ); if( food.has_flag( "CANNIBALISM" ) && !has_trait_flag( "CANNIBAL" ) ) { add_consequence( _( "The thought of eating human flesh makes you feel sick." ), CANNIBALISM ); } const bool edible = comest->comesttype == "FOOD" || food.has_flag( "USE_EAT_VERB" ); if( edible && has_effect( effect_nausea ) ) { add_consequence( _( "You still feel nauseous and will probably puke it all up again." ), NAUSEA ); } if( ( allergy_type( food ) != MORALE_NULL ) || ( carnivore && food.has_flag( "ALLERGEN_JUNK" ) && !food.has_flag( "CARNIVORE_OK" ) ) ) { add_consequence( _( "Your stomach won't be happy (allergy)." ), ALLERGY ); } if( saprophage && edible && food.rotten() && !food.has_flag( "FERTILIZER" ) ) { // Note: We're allowing all non-solid "food". This includes drugs // Hard-coding fertilizer for now - should be a separate flag later //~ No, we don't eat "rotten" food. We eat properly aged food, like a normal person. //~ Semantic difference, but greatly facilitates people being proud of their character. add_consequence( _( "Your stomach won't be happy (not rotten enough)." ), ALLERGY_WEAK ); } const int nutr = nutrition_for( food ); const int quench = comest->quench; const int temp_hunger = get_hunger() - nutr; const int temp_thirst = get_thirst() - quench; if( !has_active_mutation( trait_id( "EATHEALTH" ) ) && !has_active_mutation( trait_id( "HIBERNATE" ) ) && !has_trait( trait_id( "SLIMESPAWNER" ) ) ) { if( get_hunger() < 0 && nutr >= 5 && !has_active_mutation( trait_id( "GOURMAND" ) ) ) { add_consequence( _( "You're full already and will be forcing yourself to eat." ), TOO_FULL ); } else if( ( ( nutr > 0 && temp_hunger < stomach_capacity() ) || ( comest->quench > 0 && temp_thirst < stomach_capacity() ) ) && !food.has_infinite_charges() ) { add_consequence( _( "You will not be able to finish it all." ), TOO_FULL ); } } if( !consequences.empty() ) { if( !interactive ) { return consequences.front(); } std::ostringstream req; for( const auto &elem : consequences ) { req << elem.str() << std::endl; } const bool eat_verb = food.has_flag( "USE_EAT_VERB" ); if( eat_verb || comest->comesttype == "FOOD" ) { req << string_format( _( "Eat your %s anyway?" ), food.tname().c_str() ); } else if( !eat_verb && comest->comesttype == "DRINK" ) { req << string_format( _( "Drink your %s anyway?" ), food.tname().c_str() ); } else { req << string_format( _( "Consume your %s anyway?" ), food.tname().c_str() ); } if( !query_yn( req.str() ) ) { return consequences.front(); } } // All checks ended, it's edible (or we're pretending it is) return ret_val<edible_rating>::make_success(); }