mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 05:52:59 +00:00 
			
		
		
		
	Warnings when hitting an ally. Better warnings
This commit is contained in:
		| @@ -80,11 +80,14 @@ namespace dialog { | |||||||
|    |    | ||||||
|   map<int, reaction_t> key_actions; |   map<int, reaction_t> key_actions; | ||||||
|    |    | ||||||
|   void add_action(reaction_t action) { |   void add_key_action(int key, const reaction_t& action) { | ||||||
|     int& key = lastItem().key; |  | ||||||
|     while(key_actions.count(key)) key++; |     while(key_actions.count(key)) key++; | ||||||
|     key_actions[key] = action; |     key_actions[key] = action; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |   void add_action(const reaction_t& action) { | ||||||
|  |     add_key_action(lastItem().key, action); | ||||||
|  |     } | ||||||
|    |    | ||||||
|   void handler(int sym, int uni) { |   void handler(int sym, int uni) { | ||||||
|     dialog::handleNavigation(sym, uni); |     dialog::handleNavigation(sym, uni); | ||||||
|   | |||||||
							
								
								
									
										204
									
								
								game.cpp
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								game.cpp
									
									
									
									
									
								
							| @@ -1276,7 +1276,7 @@ bool monstersnear(stalemate1& sm) { | |||||||
|       // Krakens just destroy boats |       // Krakens just destroy boats | ||||||
|       if(c2->monst == moKrakenT && onboat(sm)) { |       if(c2->monst == moKrakenT && onboat(sm)) { | ||||||
|         if(krakensafe(c)) continue; |         if(krakensafe(c)) continue; | ||||||
|         else if(warningprotection() && res == 0) m = moWarning; |         else if(warningprotection(XLAT("This move appears dangerous -- are you sure?")) && res == 0) m = moWarning; | ||||||
|         else continue; |         else continue; | ||||||
|         } |         } | ||||||
|       // they cannot attack through vines |       // they cannot attack through vines | ||||||
| @@ -5016,32 +5016,54 @@ void sideAttack(cell *mf, int dir, eMonster who, int bonuskill) { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill) { | template<class T> void do_swords(cell *mf, cell *mt, eMonster who, const T& f) { | ||||||
|   int numsh = 0, numflail = 0, numlance = 0, numslash = 0; |  | ||||||
|    |  | ||||||
|   int backdir = neighborId(mt, mf); |  | ||||||
|    |  | ||||||
|   for(int bb=0; bb<2; bb++) if(who == moPlayer && sword::orbcount(bb)) { |   for(int bb=0; bb<2; bb++) if(who == moPlayer && sword::orbcount(bb)) { | ||||||
|     int numbb = 0; |  | ||||||
|     cell *sf = sword::pos(mf, sword::angle[multi::cpid] + (bb?S21:0)); |     cell *sf = sword::pos(mf, sword::angle[multi::cpid] + (bb?S21:0)); | ||||||
|     cell *st = sword::pos(mt, sword::shift(mf, mt, sword::angle[multi::cpid]) + (bb?S21:0)); |     cell *st = sword::pos(mt, sword::shift(mf, mt, sword::angle[multi::cpid]) + (bb?S21:0)); | ||||||
|     if(swordAttack(mt, who, st, bb)) numbb++; |     f(st, bb); | ||||||
|     if(sf != st && !isNeighbor(sf,st)) { |     if(sf != st && !isNeighbor(sf,st)) { | ||||||
|       // also attack the in-transit cell |       // also attack the in-transit cell | ||||||
|       if(S3 == 3) { |       if(S3 == 3) { | ||||||
|         forCellEx(sb, sf) if(isNeighbor(sb, st) && sb != mf && sb != mt) |         forCellEx(sb, sf) if(isNeighbor(sb, st) && sb != mf && sb != mt) f(sb, bb); | ||||||
|           if(swordAttack(mt, who, sb, bb)) numbb++; |  | ||||||
|         } |         } | ||||||
|       else { |       else { | ||||||
|         forCellEx(sb, mf) if(isNeighbor(sb, st) && sb != mt) |         forCellEx(sb, mf) if(isNeighbor(sb, st) && sb != mt) f(sb, bb); | ||||||
|           if(swordAttack(mt, who, sb, bb)) numbb++; |         forCellEx(sb, mt) if(isNeighbor(sb, sf) && sb != mf) f(sb, bb); | ||||||
|         forCellEx(sb, mt) if(isNeighbor(sb, sf) && sb != mf) |  | ||||||
|           if(swordAttack(mt, who, sb, bb)) numbb++; |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     achievement_count("SLASH", numbb, 0); |  | ||||||
|     numslash += numbb; |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | eMonster do_we_stab_a_friend(cell *mf, cell *mt, eMonster who) { | ||||||
|  |   eMonster m = moNone; | ||||||
|  |   do_swords(mf, mt, who, [&] (cell *c, int bb) {  | ||||||
|  |     if(!peace::on && canAttack(mt, who, c, c->monst, AF_SWORD) && c->monst && isFriendly(c)) m = c->monst; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |   for(int t=0; t<mf->type; t++) { | ||||||
|  |     cell *c = mf->move(t); | ||||||
|  |     if(!c) continue; | ||||||
|  |      | ||||||
|  |     bool stabthere = false; | ||||||
|  |     if(logical_adjacent(mt, who, c)) stabthere = true; | ||||||
|  |      | ||||||
|  |     if(stabthere && canAttack(mt,who,c,c->monst,AF_STAB) && isFriendly(c))  | ||||||
|  |       return c->monst; | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |   return m; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill) { | ||||||
|  |   int numsh = 0, numflail = 0, numlance = 0, numslash = 0, numbb[2]; | ||||||
|  |    | ||||||
|  |   numbb[0] = numbb[1] = 0; | ||||||
|  |  | ||||||
|  |   int backdir = neighborId(mt, mf); | ||||||
|  |    | ||||||
|  |   do_swords(mf, mt, who, [&] (cell *c, int bb) { if(swordAttack(mt, who, c, bb)) numbb[bb]++, numslash++; }); | ||||||
|  |    | ||||||
|  |   for(int bb=0; bb<2; bb++) achievement_count("SLASH", numbb[bb], 0); | ||||||
|  |  | ||||||
|   if(peace::on) return; |   if(peace::on) return; | ||||||
|    |    | ||||||
| @@ -7340,6 +7362,52 @@ bool monsterPushable(cell *c2) { | |||||||
|  |  | ||||||
| bool got_survivalist; | bool got_survivalist; | ||||||
|  |  | ||||||
|  | bool should_switchplace(cell *c1, cell *c2) { | ||||||
|  |   if(isPrincess(c2->monst) || among(c2->monst, moGolem, moIllusion, moMouse, moFriendlyGhost)) | ||||||
|  |     return true; | ||||||
|  |    | ||||||
|  |   if(peace::on) return c2->monst && !isMultitile(c2->monst); | ||||||
|  |   return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | bool warningprotection_hit(eMonster m) { | ||||||
|  |   if(m && warningprotection(XLAT("Are you sure you want to hit %the1?", m))) | ||||||
|  |     return true; | ||||||
|  |   return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | bool switchplace_prevent(cell *c1, cell *c2, bool checkonly) { | ||||||
|  |   if(!should_switchplace(c1, c2)) return false; | ||||||
|  |   if(c1->monst && c1->monst != moFriendlyIvy) { | ||||||
|  |     if(!checkonly) addMessage(XLAT("There is no room for %the1!", c2->monst)); | ||||||
|  |     return true; | ||||||
|  |     } | ||||||
|  |   if(passable(c1, c2, P_ISFRIEND | (c2->monst == moTameBomberbird ? P_FLYING : 0))) return false; | ||||||
|  |   if(warningprotection_hit(c2->monst)) return true; | ||||||
|  |   return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | void handle_switchplaces(cell *c1, cell *c2, bool& switchplaces) { | ||||||
|  |   if(should_switchplace(c1, c2)) { | ||||||
|  |     bool pswitch = false; | ||||||
|  |     if(c2->monst == moMouse) | ||||||
|  |       princess::mouseSqueak(c2); | ||||||
|  |     else if(isPrincess(c2->monst)) { | ||||||
|  |       princess::line(c2); | ||||||
|  |       princess::move(c1, c2); | ||||||
|  |       } | ||||||
|  |     else   | ||||||
|  |       pswitch = true; | ||||||
|  |     c1->hitpoints = c2->hitpoints; | ||||||
|  |     c1->stuntime = c2->stuntime; | ||||||
|  |     placeGolem(c1, c2, c2->monst); | ||||||
|  |     if(cwt.at->monst != moNone && pswitch) | ||||||
|  |       addMessage(XLAT("You switch places with %the1.", c2->monst)); | ||||||
|  |     c2->monst = moNone; | ||||||
|  |     switchplaces = true; | ||||||
|  |     } | ||||||
|  |   }   | ||||||
|  |  | ||||||
| bool movepcto(int d, int subdir, bool checkonly) { | bool movepcto(int d, int subdir, bool checkonly) { | ||||||
|   if(d >= 0 && !checkonly && subdir != 1 && subdir != -1) printf("subdir = %d\n", subdir); |   if(d >= 0 && !checkonly && subdir != 1 && subdir != -1) printf("subdir = %d\n", subdir); | ||||||
|   global_pushto = NULL; |   global_pushto = NULL; | ||||||
| @@ -7661,9 +7729,10 @@ bool movepcto(int d, int subdir, bool checkonly) { | |||||||
|         return false; |         return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |       if(c2->monst == moTameBomberbird && warningprotection_hit(moTameBomberbird)) return false; | ||||||
|  |        | ||||||
|       if(checkonly) return true; |       if(checkonly) return true; | ||||||
|        |  | ||||||
|        |  | ||||||
|       /* if(c2->monst == moTortoise) { |       /* if(c2->monst == moTortoise) { | ||||||
|         printf("seek=%d get=%d <%x/%x> item=%d\n",  |         printf("seek=%d get=%d <%x/%x> item=%d\n",  | ||||||
|           tortoise::seeking,  |           tortoise::seeking,  | ||||||
| @@ -7737,10 +7806,8 @@ bool movepcto(int d, int subdir, bool checkonly) { | |||||||
|       return false; |       return false; | ||||||
|       } |       } | ||||||
|     else { |     else { | ||||||
|       if(mineMarked(c2) && !minesafe() && !checkonly && warningprotection()) { |       if(mineMarked(c2) && !minesafe() && !checkonly && warningprotection(XLAT("Are you sure you want to step there?"))) | ||||||
|         addMessage("Are you sure you want to step there?"); |  | ||||||
|         return false; |         return false; | ||||||
|         } |  | ||||||
|       if(monstersnear(c2, NULL, moPlayer, NULL, cwt.at)) { |       if(monstersnear(c2, NULL, moPlayer, NULL, cwt.at)) { | ||||||
|         if(checkonly) return false; |         if(checkonly) return false; | ||||||
|  |  | ||||||
| @@ -7780,6 +7847,11 @@ bool movepcto(int d, int subdir, bool checkonly) { | |||||||
|           wouldkill("%The1 would kill you there!"); |           wouldkill("%The1 would kill you there!"); | ||||||
|         return false; |         return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |       if(switchplace_prevent(cwt.at, c2, checkonly)) return false; | ||||||
|  |       if(!checkonly && warningprotection_hit(do_we_stab_a_friend(cwt.at, c2, moPlayer))) | ||||||
|  |         return false; | ||||||
|  |        | ||||||
|       if(checkonly) return true; |       if(checkonly) return true; | ||||||
|       boatjump: |       boatjump: | ||||||
|       statuejump: |       statuejump: | ||||||
| @@ -7804,28 +7876,28 @@ bool movepcto(int d, int subdir, bool checkonly) { | |||||||
|         if(makeflame(cwt.at, 10, false)) markOrb(itOrbFire); |         if(makeflame(cwt.at, 10, false)) markOrb(itOrbFire); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|       { |       if(1) { | ||||||
|       bool haveIvy = false; |         bool haveIvy = false; | ||||||
|       forCellEx(c3, cwt.at) if(c3->monst == moFriendlyIvy) haveIvy = true; |         forCellEx(c3, cwt.at) if(c3->monst == moFriendlyIvy) haveIvy = true; | ||||||
|          |            | ||||||
|       bool killIvy = haveIvy; |         bool killIvy = haveIvy; | ||||||
|          |            | ||||||
|       if(items[itOrbNature]) { |         if(items[itOrbNature]) { | ||||||
|         if(c2->monst != moFriendlyIvy && strictlyAgainstGravity(c2, cwt.at, false, MF_IVY)) { |           if(c2->monst != moFriendlyIvy && strictlyAgainstGravity(c2, cwt.at, false, MF_IVY)) { | ||||||
|           invismove = false; |             invismove = false; | ||||||
|           } |             } | ||||||
|         else if(cwt.at->monst) invismove = false; |           else if(cwt.at->monst) invismove = false; | ||||||
|         else if(haveIvy || !cellEdgeUnstable(cwt.at, MF_IVY)) { |           else if(haveIvy || !cellEdgeUnstable(cwt.at, MF_IVY)) { | ||||||
|           cwt.at->monst  = moFriendlyIvy; |             cwt.at->monst  = moFriendlyIvy; | ||||||
|           cwt.at->mondir = neighborId(cwt.at, c2); |             cwt.at->mondir = neighborId(cwt.at, c2); | ||||||
|           invismove = false; |             invismove = false; | ||||||
|           markOrb(itOrbNature); |             markOrb(itOrbNature); | ||||||
|           killIvy = false; |             killIvy = false; | ||||||
|  |             } | ||||||
|           } |           } | ||||||
|  |          | ||||||
|  |         if(killIvy) killFriendlyIvy(); | ||||||
|         } |         } | ||||||
|        |  | ||||||
|       if(killIvy) killFriendlyIvy(); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       if(items[itOrbDigging]) { |       if(items[itOrbDigging]) { | ||||||
|         invismove = false; |         invismove = false; | ||||||
| @@ -7848,34 +7920,8 @@ bool movepcto(int d, int subdir, bool checkonly) { | |||||||
|        |        | ||||||
|       movecost(cwt.at, c2, 2); |       movecost(cwt.at, c2, 2); | ||||||
|  |  | ||||||
|       { |       handle_switchplaces(cwt.at, c2, switchplaces); | ||||||
|       bool pushpast = false; |              | ||||||
|       pushpast =  |  | ||||||
|         c2->monst == moGolem || c2->monst == moIllusion || isPrincess(c2->monst) || c2->monst == moMouse || |  | ||||||
|         c2->monst == moFriendlyGhost; |  | ||||||
|        |  | ||||||
|       if(peace::on) pushpast |= c2->monst && !isMultitile(c2->monst); |  | ||||||
|        |  | ||||||
|       if(pushpast) { |  | ||||||
|         bool pswitch = false; |  | ||||||
|         if(c2->monst == moMouse) |  | ||||||
|           princess::mouseSqueak(c2); |  | ||||||
|         else if(isPrincess(c2->monst)) { |  | ||||||
|           princess::line(c2); |  | ||||||
|           princess::move(cwt.at, c2); |  | ||||||
|           } |  | ||||||
|         else   |  | ||||||
|           pswitch = true; |  | ||||||
|         cwt.at->hitpoints = c2->hitpoints; |  | ||||||
|         cwt.at->stuntime = c2->stuntime; |  | ||||||
|         placeGolem(cwt.at, c2, c2->monst); |  | ||||||
|         if(cwt.at->monst != moNone && pswitch) |  | ||||||
|           addMessage(XLAT("You switch places with %the1.", c2->monst)); |  | ||||||
|         c2->monst = moNone; |  | ||||||
|         switchplaces = true; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|        |  | ||||||
|       mountjump: |       mountjump: | ||||||
|       lastmovetype = lmMove; lastmove = cwt.at; |       lastmovetype = lmMove; lastmove = cwt.at; | ||||||
|  |  | ||||||
| @@ -8087,11 +8133,27 @@ bool minesafe() { | |||||||
|   return items[itOrbAether]; |   return items[itOrbAether]; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| bool warningprotection() { | bool warningprotection(const string& s) { | ||||||
|   if(hardcore) return false; |   if(hardcore) return false; | ||||||
|   if(multi::activePlayers() > 1) return false; |   if(multi::activePlayers() > 1) return false; | ||||||
|   if(items[itWarning]) return false; |   if(items[itWarning]) return false; | ||||||
|   items[itWarning] = 1; |   pushScreen([s] () { | ||||||
|  |     gamescreen(1); | ||||||
|  |     dialog::addBreak(250); | ||||||
|  |     dialog::init(XLAT("WARNING"), 0xFF0000, 150, 100); | ||||||
|  |     dialog::addBreak(500); | ||||||
|  |     dialog::addInfo(s); | ||||||
|  |     dialog::addBreak(500); | ||||||
|  |     dialog::addItem(XLAT("YES"), 'y'); | ||||||
|  |     dialog::lastItem().scale = 200; | ||||||
|  |     auto yes = [] () { items[itWarning] = 1; popScreen(); }; | ||||||
|  |     dialog::add_action(yes); | ||||||
|  |     dialog::add_key_action(SDLK_RETURN, yes); | ||||||
|  |     dialog::addItem(XLAT("NO"), 'n'); | ||||||
|  |     dialog::lastItem().scale = 200; | ||||||
|  |     dialog::add_action([] () { items[itWarning] = 0; popScreen(); }); | ||||||
|  |     dialog::display(); | ||||||
|  |     }); | ||||||
|   return true; |   return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								hyper.h
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								hyper.h
									
									
									
									
									
								
							| @@ -1721,7 +1721,7 @@ void killThePlayer(eMonster m, int id, flagtype flags); | |||||||
| bool attackJustStuns(cell *c2, flagtype flags); | bool attackJustStuns(cell *c2, flagtype flags); | ||||||
|  |  | ||||||
| bool isTargetOrAdjacent(cell *c); | bool isTargetOrAdjacent(cell *c); | ||||||
| bool warningprotection(); | bool warningprotection(const string& s); | ||||||
| bool mineMarked(cell *c); | bool mineMarked(cell *c); | ||||||
| bool minesafe(); | bool minesafe(); | ||||||
| bool hasSafeOrb(cell *c); | bool hasSafeOrb(cell *c); | ||||||
| @@ -1846,7 +1846,8 @@ namespace dialog { | |||||||
|    |    | ||||||
|   void addHelp(); |   void addHelp(); | ||||||
|   void addBack(); |   void addBack(); | ||||||
|   void add_action(reaction_t action); |   void add_action(const reaction_t& action); | ||||||
|  |   void add_key_action(int key, const reaction_t& action); | ||||||
|    |    | ||||||
|   string view_edited_string(); |   string view_edited_string(); | ||||||
|   void start_editing(string& s); |   void start_editing(string& s); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Zeno Rogue
					Zeno Rogue