mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 14:02:59 +00:00 
			
		
		
		
	multi:: PvP, friendly-fire, and self-hits options
This commit is contained in:
		| @@ -135,6 +135,8 @@ EX bool wrongMode(char flags) { | ||||
|     dls = lsChaos; | ||||
|  | ||||
|   if(land_structure != dls) return true; | ||||
|   if(numplayers() > 1 && !multi::friendly_fire) return true; | ||||
|   if(numplayers() > 1 && multi::pvp_mode) return true; | ||||
|   if((numplayers() > 1) != (flags == rg::multi)) return true; | ||||
|   return false; | ||||
|   } | ||||
| @@ -778,6 +780,9 @@ EX void achievement_final(bool really_final) { | ||||
|   if(geometry) return; | ||||
|   if(NONSTDVAR) return; | ||||
|  | ||||
|   if(numplayers() > 1 && !multi::friendly_fire) return; | ||||
|   if(numplayers() > 1 && multi::pvp) return; | ||||
|    | ||||
|   // determine the correct leaderboard ID for 'total score' | ||||
|   // or return if no leaderboard for the current mode | ||||
|   int sid; | ||||
|   | ||||
| @@ -168,7 +168,7 @@ EX int lightat, safetyat; | ||||
| EX void drawLightning() { lightat = ticks; } | ||||
| EX void drawSafety() { safetyat = ticks; } | ||||
|  | ||||
| void drawShield(const shiftmatrix& V, eItem it) { | ||||
| EX void drawShield(const shiftmatrix& V, eItem it) { | ||||
| #if CAP_CURVE | ||||
|   float ds = ptick(300); | ||||
|   color_t col = iinf[it].color; | ||||
|   | ||||
							
								
								
									
										39
									
								
								multi.cpp
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								multi.cpp
									
									
									
									
									
								
							| @@ -29,6 +29,9 @@ EX namespace multi { | ||||
|   EX charstyle scs[MAXPLAYER]; | ||||
|  | ||||
|   EX bool split_screen; | ||||
|   EX bool pvp_mode; | ||||
|   EX bool friendly_fire = true; | ||||
|   EX bool self_hits; | ||||
|  | ||||
|   EX int players = 1; | ||||
|   EX cellwalker player[MAXPLAYER]; | ||||
| @@ -39,7 +42,7 @@ EX namespace multi { | ||||
|   EX bool flipped[MAXPLAYER]; | ||||
|    | ||||
|   // treasure collection, kill, and death statistics | ||||
|   EX int treasures[MAXPLAYER], kills[MAXPLAYER], deaths[MAXPLAYER]; | ||||
|   EX int treasures[MAXPLAYER], kills[MAXPLAYER], deaths[MAXPLAYER], pkills[MAXPLAYER], suicides[MAXPLAYER]; | ||||
|    | ||||
|   EX bool alwaysuse = false; | ||||
|  | ||||
| @@ -194,18 +197,21 @@ string listkeys(int id) { | ||||
| #define SCJOY 16 | ||||
|  | ||||
| string dsc(int id) { | ||||
|   char buf[64]; | ||||
|   sprintf(buf, " (%d $$$, %d kills, %d deaths)",  | ||||
|     multi::treasures[id], | ||||
|     multi::kills[id], | ||||
|     multi::deaths[id] | ||||
|   string buf = XLAT(" (%d $$$, %d kills, %d deaths)", | ||||
|     its(multi::treasures[id]), | ||||
|     its(multi::kills[id]), | ||||
|     its(multi::deaths[id]) | ||||
|     ); | ||||
|   if(friendly_fire) | ||||
|     buf += XLAT(" (%d pkills)", its(multi::pkills[id])); | ||||
|   if(self_hits) | ||||
|     buf += XLAT(" (%d self)", its(multi::suicides[id])); | ||||
|   return buf; | ||||
|   } | ||||
|  | ||||
| EX void resetScores() { | ||||
|   for(int i=0; i<MAXPLAYER; i++) | ||||
|     multi::treasures[i] = multi::kills[i] = multi::deaths[i] = 0; | ||||
|     multi::treasures[i] = multi::kills[i] = multi::deaths[i] = multi::pkills[i] = multi::suicides[i] = 0; | ||||
|   } | ||||
|   | ||||
| bool configdead; | ||||
| @@ -522,6 +528,19 @@ EX void showConfigureMultiplayer() { | ||||
|     dialog::addSelItem(XLAT("keyboard & joysticks"), "", 'k'); | ||||
|     dialog::add_action(multi::configure); | ||||
|     add_edit(split_screen); | ||||
|     if(shmup::on && !racing::on) { | ||||
|       add_edit(pvp_mode); | ||||
|       add_edit(friendly_fire); | ||||
|       add_edit(self_hits); | ||||
|       if(pvp_mode) | ||||
|         dialog::addInfo(XLAT("PvP grants infinite lives -- achievements disabled")); | ||||
|       else if(friendly_fire) | ||||
|         dialog::addInfo(XLAT("friendly fire off -- achievements disabled")); | ||||
|       else | ||||
|         dialog::addBreak(100); | ||||
|       } | ||||
|     else | ||||
|       dialog::addInfo(XLAT("PvP available only in shmup")); | ||||
|     } | ||||
|   else dialog::addBreak(200); | ||||
|    | ||||
| @@ -695,6 +714,12 @@ EX void initConfig() { | ||||
|   addsaver(multi::players, "mode-number of players"); | ||||
|   param_b(multi::split_screen, "splitscreen", false) | ||||
|     ->editable("split screen mode", 's'); | ||||
|   param_b(multi::pvp_mode, "pvp_mode", false) | ||||
|     ->editable("player vs player", 'v'); | ||||
|   param_b(multi::friendly_fire, "friendly_fire", true) | ||||
|     ->editable("friendly fire", 'f'); | ||||
|   param_b(multi::self_hits, "self_hits", false) | ||||
|     ->editable("self hits", 'h'); | ||||
|   addsaver(alwaysuse, "use configured keys");   | ||||
|   // unfortunately we cannot use key names here because SDL is not yet initialized | ||||
|   for(int i=0; i<512; i++) | ||||
|   | ||||
							
								
								
									
										44
									
								
								shmup.cpp
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								shmup.cpp
									
									
									
									
									
								
							| @@ -50,8 +50,9 @@ struct monster { | ||||
|   int nextshot;    ///< when will it be able to shot (players/flailers) | ||||
|   int pid;         ///< player ID | ||||
|   int hitpoints;   ///< hitpoints; or time elapsed in Asteroids | ||||
|   int stunoff; | ||||
|   int blowoff; | ||||
|   int stunoff;     ///< when does the stun end | ||||
|   int blowoff;     ///< when does the blow end | ||||
|   int fragoff;     ///< when does the frag end in PvP | ||||
|   double swordangle; ///< sword angle wrt at | ||||
|   double vel;        ///< velocity, for flail balls | ||||
|   double footphase; | ||||
| @@ -65,7 +66,7 @@ struct monster { | ||||
|  | ||||
|   monster() {  | ||||
|     dead = false; inBoat = false; parent = NULL; nextshot = 0;  | ||||
|     stunoff = 0; blowoff = 0; footphase = 0; no_targetting = false; | ||||
|     stunoff = 0; blowoff = 0; fragoff = 0; footphase = 0; no_targetting = false; | ||||
|     swordangle = 0; inertia = Hypc; ori = Id; refs = 1;     | ||||
|     split_tick = -1; split_owner = -1; | ||||
|     } | ||||
| @@ -270,6 +271,12 @@ void killMonster(monster* m, eMonster who_kills, flagtype flags = 0) { | ||||
|   if(callhandlers(false, hooks_kill, m)) return; | ||||
|   if(m->dead) return; | ||||
|   m->dead = true; | ||||
|   if(isPlayer(m)) { | ||||
|     if(multi::cpid == m->pid) | ||||
|       multi::suicides[multi::cpid]++; | ||||
|     else if(multi::cpid >= 0) | ||||
|       multi::pkills[multi::cpid]++; | ||||
|     } | ||||
|   if(isBullet(m) || isPlayer(m)) return; | ||||
|   m->stk = m->base->monst; | ||||
|   if(m->inBoat && isWatery(m->base)) { | ||||
| @@ -400,6 +407,9 @@ ld bullet_velocity(eMonster t) { | ||||
|  | ||||
| int frontdir() { return WDIM == 2 ? 0 : 2; } | ||||
|  | ||||
| /** cannot hit yourself during first 100ms after shooting a bullet */ | ||||
| const int bullet_time = 100; | ||||
|  | ||||
| void shootBullet(monster *m) { | ||||
|   monster* bullet = new monster; | ||||
|   bullet->base = m->base; | ||||
| @@ -412,6 +422,7 @@ void shootBullet(monster *m) { | ||||
|   bullet->inertia = m->inertia; | ||||
|   bullet->inertia[frontdir()] += bullet_velocity(m->type) * SCALE; | ||||
|   bullet->hitpoints = 0; | ||||
|   bullet->fragoff = ticks + bullet_time; | ||||
|  | ||||
|   additional.push_back(bullet); | ||||
|    | ||||
| @@ -429,6 +440,7 @@ void shootBullet(monster *m) { | ||||
|     bullet->set_parent(m); | ||||
|     bullet->pid = m->pid; | ||||
|     bullet->hitpoints = 0; | ||||
|     bullet->fragoff = ticks + bullet_time; | ||||
|     bullet->inertia = cspin(0, WDIM-1, -M_PI/4 * i) * m->inertia; | ||||
|     bullet->inertia[frontdir()] += bullet_velocity(m->type) * SCALE; | ||||
|     additional.push_back(bullet); | ||||
| @@ -1755,8 +1767,10 @@ void moveBullet(monster *m, int delta) { | ||||
|  | ||||
|   // items[itOrbWinter] = 100; items[itOrbLife] = 100; | ||||
|    | ||||
|   bool no_self_hits = !multi::self_hits || m->fragoff > ticks; | ||||
|  | ||||
|   if(!m->isVirtual) for(monster* m2: nonvirtual) { | ||||
|     if(m2 == m || (m2 == m->parent && m->vel >= 0) || m2->parent == m->parent)  | ||||
|     if(m2 == m || (m2 == m->parent && no_self_hits) || (m2->parent == m->parent && no_self_hits)) | ||||
|       continue; | ||||
|      | ||||
|     if(m2->dead) continue; | ||||
| @@ -1765,7 +1779,9 @@ void moveBullet(monster *m, int delta) { | ||||
|     if(m2->type == moFlailer && m2 != m->parent) continue; | ||||
|     // be nice to your images! would be too hard otherwise... | ||||
|     if(isPlayerOrImage(parentOrSelf(m)->type) && isPlayerOrImage(parentOrSelf(m2)->type) && | ||||
|       m2->pid == m->pid) | ||||
|       m2->pid == m->pid && no_self_hits) | ||||
|       continue; | ||||
|     if(isPlayer(parentOrSelf(m)) && isPlayer(m2) && m2->pid != m->pid && !friendly_fire) | ||||
|       continue; | ||||
|     // fireballs/airballs don't collide | ||||
|     if(m->type == moFireball && m2->type == moFireball) continue; | ||||
| @@ -2538,6 +2554,9 @@ EX void fixStorage() { | ||||
|  | ||||
| EX hookset<bool(int)> hooks_turn; | ||||
|  | ||||
| /** the amount of time chars are disabled in PvP */ | ||||
| EX int pvp_delay = 2000; | ||||
|  | ||||
| EX void turn(int delta) { | ||||
|  | ||||
|   if(split_screen && subscreens::split( [delta] () { turn(delta); })) return; | ||||
| @@ -2754,6 +2773,15 @@ EX void turn(int delta) { | ||||
|         orbused[itOrbShield] = true; | ||||
|         } | ||||
|  | ||||
|       if(pc[i]->dead && pvp_mode) { | ||||
|         pc[i]->dead = false; | ||||
|         if(ticks > pc[i]->fragoff) { | ||||
|           pc[i]->fragoff = ticks + pvp_delay; | ||||
|           pc[i]->nextshot = min(pc[i]->nextshot, pc[i]->fragoff); | ||||
|           multi::deaths[i]++; | ||||
|           } | ||||
|         } | ||||
|      | ||||
|       if(pc[i]->dead && items[itOrbLife]) { | ||||
|         multi::deaths[i]++; | ||||
|         items[itOrbLife]--; | ||||
| @@ -3033,7 +3061,11 @@ bool celldrawer::draw_shmup_monster() { | ||||
|               } | ||||
|             } | ||||
|           if(m->inBoat) m->footphase = 0; | ||||
|           if(mapeditor::drawplayer) drawMonsterType(moPlayer, c, view, 0xFFFFFFC0, m->footphase, 0xFFFFFFC0); | ||||
|           if(mapeditor::drawplayer) { | ||||
|             if(m->fragoff > ticks) | ||||
|               drawShield(view, itWarning); | ||||
|             drawMonsterType(moPlayer, c, view, 0xFFFFFFC0, m->footphase, 0xFFFFFFC0); | ||||
|             } | ||||
|           } | ||||
|  | ||||
|         if(ths && h) first_cell_to_draw = false; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Zeno Rogue
					Zeno Rogue