// compute 1/30th of a second
void update_sim()
{
	//printf("Sim Update\n" );
	if (!g_game.currLevel) {
		// no level loaded, don't update
		return;
	}

	// move aim thinggy based on cfHeading
	g_game.aimdir += g_game.cfAimDir * 10.0f;
	if (g_game.aimdir < 0.0f) g_game.aimdir += 360.0f;
	if (g_game.aimdir > 360.0f) g_game.aimdir -= 360.0f;	

	// update power charge
	if (g_game.isCharging) {
		g_game.charge_amt += SIM_STEP;
		if (g_game.charge_amt > 2.0f) {
			g_game.charge_amt = 2.0f;
			fire_shot();
			g_game.isCharging = false;
		}
	}

	// update any moving nodes
	bool needCleanup = false;
	g_game.isUpdating = false;
	for (size_t ndx=0; ndx < g_game.currLevel->m_nodes.size(); ndx++) {
			KNode &n = g_game.currLevel->m_nodes[ndx];
			if (n.v > MIN_VEL) {

				// flag that something is being updated
				g_game.isUpdating = true;

				// update in kudzu space (bad)
				//n.pos += (n.dir * n.v);
				vec3f pos2;
				vec3f pos, dir, nrm, nrm2, bary,b2;
				KSimTri tri;
				if (!g_game.currLevel->getSimInfo( n.pos, n.dir, 
						pos, nrm, dir, tri, bary ) ) {
					// node went out of bounds, mark it for
					// removal					
					needCleanup = true;
					n.erase_flag = true;
				} else {					
					n.erase_flag = false;

					// update
					vec3f oldpos = pos;
					pos	= pos +	dir	* (n.v * SIM_STEP);

					// Add a bunch every BUNCH_SPC					
					float d = prmath::Length( pos - oldpos );
					n.bdist += d;
					if (n.bdist > BUNCH_SPC) {
						n.bdist -= BUNCH_SPC;
						KBunch b;
						b.pos = n.pos;
						b.pos3 = oldpos;
						b.age = 0.0f;
						g_game.currLevel->m_bunches.push_back( b );						
					}

					// make pos2 a little further for boundry crossing thing
					pos2 = pos + dir * (n.v	* (SIM_STEP*5)); 

					// remember	pos3
					n.pos3 = pos;

					// convert pos back	to uv space
					b2 = tri.pos2bary( pos );				
					n.pos =	tri.bary2uv( b2	);

					// apply drag
					n.v	-= 0.02;

					// if new pos is outside of	triangle, 
					// update dir so it	will still appear straight
					if ((b2.x <	0) || (b2.y	< 0) ||	(b2.z <	0))	{
						// b2 went outside of tri, get the new tri
						g_game.currLevel->getSimInfo( n.pos, n.dir,	
							pos, nrm2, dir,	tri, bary );

						// find	what uv's the new tri would	give for the old position					
						b2 = tri.pos2bary( pos2	);
						vec2f uv2 =	tri.bary2uv( b2	);

						// get new heading from	uv2	-> uv, if triangles	
						// are near	flat
						float olddir = n.dir;
						float ang =	acos( prmath::DotProduct( nrm, nrm2	));
						printf("Angle: %f\n", R2D*ang );
						if (ang	< D2R*45 ) {
							n.dir =	R2D	* atan2( uv2.y - n.pos.y, uv2.x	- n.pos.x  );					
							printf("DBG: Adjusting:	Old	dir	was	%f new dir %f\n", olddir, n.dir	);
						} else {
							// give	the	angle a	random nudge to	hide the
							// distortion in mapping
							n.dir += (((float)rand() / (float)RAND_MAX)- 0.5f) * 45.0;
							printf("DBG: Jittering:	Old	dir	was	%f new dir %f\n", olddir, n.dir	);
						}
					}					
					
					// kill anything that runs into a bunch
					for (int i=0; i < g_game.currLevel->m_bunches.size(); i++) {

						// ignore freshly planted bunches
						if (g_game.currLevel->m_bunches[i].age < 2.0f) continue;

						float d = prmath::Length(n.pos3 - g_game.currLevel->m_bunches[i].pos3);					
						if (d < BUNCH_SPC* 0.5) {
							printf("KILL node %d Dist %f %f\n", 
								ndx, d, BUNCH_SPC*0.25 );
							n.erase_flag = true;
							needCleanup = true;
							break;
						}
					}					

					
			} // end of update
		} else {
			// node is stationary
			if (n.explode_flag) {
				needCleanup = true;
				n.erase_flag = true;
			}
		}

	} // end of node loop


	// safety: kill any bunches next to a not moving node
	std::vector<KBunch> newbunch;
	for (int i=0; i < g_game.currLevel->m_bunches.size(); i++) {
		KBunch &b = g_game.currLevel->m_bunches[i];
		bool touching = false;
		for (int j=0; j < g_game.currLevel->m_nodes.size(); j++) {
			KNode &n = g_game.currLevel->m_nodes[j];
			// skip moving nodes
			if (n.v > MIN_VEL) continue;

			if (prmath::Length( b.pos3 - n.pos3 ) < BUNCH_SPC * 0.55 ) {
				touching = true;
				break;
			}
		}

		if (!touching) {
			newbunch.push_back( b );
		}
	}
	g_game.currLevel->m_bunches = newbunch;

	// age all of the bunches
	for (int i=0; i < g_game.currLevel->m_bunches.size(); i++) {
		g_game.currLevel->m_bunches[i].age += SIM_STEP;
	}

	// rebuild node list if there were baddies
	if (needCleanup) {

		// reset active node to 0
		g_game.activeNode = 0;

		// Remove any nodes with the erase_flag set
		std::vector<KNode> newlist;
		for (int i=0; i < g_game.currLevel->m_nodes.size(); i++) {
			KNode &n = g_game.currLevel->m_nodes[i];
			if (!n.erase_flag) {
				newlist.push_back( n );
			}
		}
		g_game.currLevel->m_nodes = newlist;

	}
	
}
// main loop
int main( int argc, char *argv[] )
{
		if ( SDL_Init(SDL_INIT_NOPARACHUTE |SDL_INIT_VIDEO |SDL_INIT_JOYSTICK) < 0 ) {
        fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
        exit(1);
    }

	if( SDL_SetVideoMode( 800, 600, 16, SDL_OPENGL /*| SDL_FULLSCREEN */ ) == 0 ) {
		fprintf(stderr,	"Unable to set video mode: %s\n", SDL_GetError());
        exit(1);
	}

	SDL_WM_SetCaption( "Kudzu Commander", NULL );


	while (1) {		
    SDL_Event event;

    /* Grab all the events off the queue. */
    while( SDL_PollEvent( &event ) ) {
		
        switch( event.type ) {
        case SDL_KEYDOWN:
            switch( event.key.keysym.sym ) {
				case SDLK_ESCAPE:
					do_quit();
					break;				

				case SDLK_SPACE:
					if (!g_game.isUpdating) {
						g_game.isCharging = true;
						g_game.charge_amt = 0.0;
					}
					break;

				case SDLK_RETURN:
					// EXPLODE node
					// don't fire a shot until current one is done, 
					// and can't explode if there is only one node left
					if ((!g_game.isUpdating) && (g_game.currLevel->m_nodes.size() > 1 )) {
						// TODO: energy system								
						int num_explode = 20;
						for (int i = 0; i < num_explode; i++ ) {
							KNode n;
							n.pos = g_game.GetActNode().pos;						
							n.dir = ((float)i / float(num_explode)) * 360.0f;
							n.v = 2.0;
							n.bdist = ( (float)rand() / (float)RAND_MAX) * BUNCH_SPC;
							n.explode_flag = true;
						
							g_game.currLevel->m_nodes.push_back( n );
						}
						g_game.GetActNode().erase_flag = true;
						g_game.activeNode = 0;
					}
					break;				


				case SDLK_s:
					//ilutGLScreenie();
					break; 

				case SDLK_1:
					g_dbg.drawGameView = !g_dbg.drawGameView;
					printf("Game View is now: %s\n", g_dbg.drawGameView?"enabled":"disabled" );
					break;

				case SDLK_2:
					g_dbg.drawDbgView = !g_dbg.drawDbgView;
					printf("Debug View is now: %s\n", g_dbg.drawDbgView?"enabled":"disabled" );
					break;				

				case SDLK_3:
					g_dbg.drawSimView = !g_dbg.drawSimView;
					printf("Sim View is now: %s\n", g_dbg.drawSimView?"enabled":"disabled" );
					break;

				case SDLK_l: 
					{
					// init level
					printf("Init level\n");
					g_game.currLevel = new KLevel();
					// TODO: load this from a level info file
					g_game.currLevel->loadSimMesh( "./gamedata/house_sim.obj" );
					//g_game.currLevel->loadSimMesh( "./gamedata/grid_sim.obj" );

					// staring node
					KNode n;
					n.pos = vec2f( 0.1f, 0.5f );
					n.pos3 = g_game.currLevel->k2pos( n.pos );
					n.erase_flag = false;
					n.explode_flag = false;
					g_game.currLevel->m_nodes.push_back( n );
					}
					break;				

				case SDLK_q:
					if (g_game.currLevel) {
						g_dbg.dbgTriNdx--;
						if (g_dbg.dbgTriNdx < 0 ) {
							g_dbg.dbgTriNdx = g_game.currLevel->m_tri.size()-1;
						}

						printf("Triangle %d, links ab %d bc %d ca %d\n",
							g_dbg.dbgTriNdx,
							g_game.currLevel->m_tri[g_dbg.dbgTriNdx].ablink,
							g_game.currLevel->m_tri[g_dbg.dbgTriNdx].bclink,
							g_game.currLevel->m_tri[g_dbg.dbgTriNdx].calink );
					}
					break;

				case SDLK_w:
					if (g_game.currLevel) {
						g_dbg.dbgTriNdx++;
						if (g_dbg.dbgTriNdx >= g_game.currLevel->m_tri.size() ) {
							g_dbg.dbgTriNdx = 0;
						}
					}
					break;				

				case SDLK_UP:
					if (g_game.currLevel) {
						g_game.activeNode++;
						if (g_game.activeNode == g_game.currLevel->m_nodes.size()) {
							g_game.activeNode = 0;
						}
					}
					break;

				case SDLK_DOWN:
					if (g_game.currLevel) {
						g_game.activeNode--;
						if (g_game.activeNode < 0) {
							g_game.activeNode = g_game.currLevel->m_nodes.size() - 1;
						}
					}
					break;
				
				default:
					break;
				}
			break;

			case SDL_KEYUP:
				switch( event.key.keysym.sym ) {					
					case SDLK_SPACE:
					if ((!g_game.isUpdating) && (g_game.isCharging)) {
						fire_shot();
					}					

					break;		
				}

			case SDL_MOUSEMOTION:
				if (SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(3)) {
					// dragging RMB
					printf("Dragging %d %d\n", 
						event.motion.xrel, event.motion.yrel );
					g_cam.heading += -((float)event.motion.xrel / 800.0f) * 90.0f;
					printf("g_cam.heading %f\n", g_cam.heading );
					if (g_cam.heading < 0.0f) g_cam.heading += 360.0f;
					if (g_cam.heading > 360.0f) g_cam.heading -= 360.0f;
					g_cam.recalc();
				}

				// update mouse pos on sim view
				if ( (g_dbg.drawSimView) || (g_dbg.drawDbgView) ) {
					g_dbg.mx = (float)(event.motion.x - 110) / 580.0;
					g_dbg.my = 1.0f - ((float)(event.motion.y - 10) / 580.0);
				}

				break;
			case SDL_MOUSEBUTTONDOWN:
				if (event.button.button==4) {
					// wheel up
					g_cam.dist *= ZOOM_AMT;
					g_cam.recalc();
				} else if (event.button.button==5) {
					// wheel down
					g_cam.dist *= (1.0f / ZOOM_AMT);
					g_cam.recalc();
				} else if (event.button.button==2) {
					if ((g_dbg.mx >= 0.0) && (g_dbg.mx <= 1.0) &&
						(g_dbg.my >= 0.0) && (g_dbg.my <= 1.0) ) {
						g_dbg.dbgBaryCursor = vec2f( g_dbg.mx, g_dbg.my );
					}
				}
				printf("Mouse button %d pressed at (%d,%d)\n",
                       event.button.button, event.button.x, event.button.y);
				break;
		
			case SDL_QUIT:
				/* Handle quit requests (like Ctrl-c). */
				do_quit();
				break;
			}	
		}

		// Continuous (not one shot) keypresses
		g_game.cfAimDir = 0.0f;
		Uint8 *keys;
		keys = SDL_GetKeyState(NULL);
		if (keys[SDLK_LEFT] && !keys[SDLK_RIGHT]) {
			g_game.cfAimDir = 1.0;
		}
		if (!keys[SDLK_LEFT] && keys[SDLK_RIGHT]) {
			g_game.cfAimDir = -1.0;
		}

		// Update game loop	
		static Uint32 last_tick=0, sim_ticks = 0;		
		Uint32 tick;
		tick = SDL_GetTicks();
		Uint32 deltaT;

		// get elapsed time
		if (last_tick==0) {		
			deltaT = 0;
		} else {
			deltaT = tick - last_tick;
		}
		last_tick = tick;

		// update every SIM_FRAME_TIME ticks 
		sim_ticks += deltaT;
		while (sim_ticks > SIM_FRAME_TIME) {
			sim_ticks -= SIM_FRAME_TIME;
			update_sim();
		}

		// Redraw the screen
		redraw();
	}


	return 0;
}
Exemplo n.º 3
0
void act(gamedata &g, int jx, int jy, bool jb){

  // Reset hidden/afterburner status
  g.p().hide = false;
  g.p().boost = false;
  g.p().gunthreat = 0;

  switch(g.p().state){
    case 0: // OK planes

      switch(g.p().land){
        case 0: // Stationary on runway
          // Check for mission 0 and mission 1 wins
          if (((g.mission == 0) || (g.mission == 1)) && (!g.p().drak) &&
              (g.p().score >= g.targetscore)){
            g.winner = g.p().side;
          }
          // Start Engine
          if (jy == -1){
            g.p().s = 0.3*GAME_SPEED*GAME_SPEED;
            g.p().land = 1;
            if ((g.p().control) > 0){
              g.sound.volume(g.p().control-1, 0.0);
              g.sound.loop(g.p().control-1, g.p().enginesample);
            }
          }
          break;

        case 1: // Taking off plane
          if (jy == -1){
            g.p().s = dlimit(g.p().s + 0.3*GAME_SPEED*GAME_SPEED, 0.0,
                            6.0*GAME_SPEED);
          }
          // Take off plane
          if ((jx == -1) && (g.p().s > 2.0*GAME_SPEED) &&
              (g.base[g.p().side].planed == 13)){
            g.p().d++;
            g.p().rotate = g.p().maxrotate;
            g.p().land = 2;
          }
          if ((jx == 1) && (g.p().s > 2.0*GAME_SPEED) &&
              (g.base[g.p().side].planed == 5)){
            g.p().d--;
            g.p().rotate = g.p().maxrotate;
            g.p().land = 2;
          }
          // Off end of runway
          if (abs(int(g.p().x - g.base[g.p().side].planex)) >
               g.base[g.p().side].runwaylength){
            g.p().land = 2;
          }
          break;

        case 2: // flying
          // Navigate plane
          if ((g.p().rotate == 0) && (jx !=0)){
            g.p().d = wrap(g.p().d-jx,1,17);
            g.p().rotate = g.p().maxrotate;
          }else{
            if (g.p().rotate > 0){
              g.p().rotate--;
            }
          }
          // Acceleration / Afterburner Controls
          {
            double acceleration = g.accel[g.p().d] * GAME_SPEED * GAME_SPEED;
            if (g.p().burner){
              if (jy == -1){
                acceleration += 0.3*GAME_SPEED*GAME_SPEED;
                g.p().boost = true;
              }
              if ((g.p().s > 6.0*GAME_SPEED) && (jy != -1)){
                acceleration -= 0.3*GAME_SPEED*GAME_SPEED;
              }
              g.p().s = dlimit(g.p().s + acceleration, 0.0, 12.0*GAME_SPEED);
            }else{
              g.p().s = dlimit(g.p().s + acceleration, 0.0, 6.0*GAME_SPEED);
            }
          }
          // Stealth Controls
          if ((jy == -1) && (jx == 0) && (!jb) && (g.p().stealth)){
            g.p().hide = true;
          }
          // Check for shotfire
          if (g.p().shotdelay == 0){
            if ((jb) && (g.p().ammo > 0)){
              fire_shot(g.p(), g.shot, g.sound, g.xmove, g.ymove);              
            }
            // Check for bombdrop
            if ((jy == 1) && (g.p().bombs > 0)){
              drop_bomb(g.p(), g.fall, g.sound, g.bombimage);
            }
          }else{
            g.p().shotdelay--;
          }
          break;

        case 3: // Landing plane
          if ((((g.p().x - g.base[g.p().side].planex) < 2.0) &&
               (g.base[g.p().side].planed == 13)) ||
              (((g.p().x - g.base[g.p().side].planex) > -2.0) &&
               (g.base[g.p().side].planed == 5))){
            g.p().land = 0;
            g.p().x = g.base[g.p().side].planex;
            g.p().y = g.base[g.p().side].planey;
            g.p().d = g.base[g.p().side].planed;
            g.p().xs = 0;
            g.p().ys = 0;
            g.p().s = 0;
            g.p().ammo = g.p().maxammo;
            g.p().bombs = g.p().maxbombs;
            g.p().coms = 0;
            g.p().targetx = 0;
            g.p().targety = 0;
            g.p().cruiseheight = 0;
          }
          break;
      }
      // Set speed for planes
      g.p().xs = g.p().s * g.xmove[g.p().d];
      g.p().ys = g.p().s * g.ymove[g.p().d];
      // Check for stall
      if ((g.p().s < 1.0*GAME_SPEED) && (g.p().land == 2)){
        g.p().state = 1;
        if ((g.p().control) > 0){
          g.sound.stop(g.p().control-1);
          g.sound.play(SOUND_STALL);
        }
      }
      if (g.p().y < 0){
        g.p().y = 0;
        g.p().ys = 0;
        g.p().state = 1;
        if ((g.p().control) > 0){
          g.sound.stop(g.p().control-1);
          g.sound.play(SOUND_STALL);
        }
      }
      break;

    case 1: // Stalling planes
      // Navigate plane
      if ((g.p().rotate == 0) && (jx !=0)){
        g.p().d = wrap(g.p().d-jx,1,17);
        g.p().rotate = g.p().maxrotate;
      }else{
        if (g.p().rotate > 0){
          g.p().rotate--;
        }
      }
      // Check for shotfire
      if (g.p().shotdelay == 0){
        if ((jb) && (g.p().ammo > 0)){
          fire_shot(g.p(), g.shot, g.sound, g.xmove, g.ymove);
        }
        // Check for bombdrop
        if ((jy == 1) && (g.p().bombs > 0)){
          drop_bomb(g.p(), g.fall, g.sound, g.bombimage);
        }
      }else{
        g.p().shotdelay--;
      }
      // Gravity and drag
      g.p().ys += 0.1 * GAME_SPEED * GAME_SPEED;
      if (fabs(g.p().xs) > 0.02 * GAME_SPEED * GAME_SPEED){
        g.p().xs -= g.p().xs / fabs(g.p().xs) * 0.02 * GAME_SPEED * GAME_SPEED;
      }
      // Recover from Stall
      if ((g.p().ys > 3.0 * GAME_SPEED) && (g.p().d == 9)){
        g.p().s = dlimit(g.p().ys, 3.0*GAME_SPEED, 6.0*GAME_SPEED);
        g.p().state = 0;
        g.p().xs = g.p().s * g.xmove[g.p().d];
        g.p().ys = g.p().s * g.ymove[g.p().d];
        g.p().coms = 0;
        if ((g.p().control) > 0){
          double volume = g.p().s / (6.0*GAME_SPEED);
          g.sound.volume(g.p().control-1, volume * 0.5);
          g.sound.loop(g.p().control-1, g.p().enginesample);
        }
      }
      break;

    case 2: // Dead planes
      // Gravity and drag
      g.p().ys += 0.1 * GAME_SPEED * GAME_SPEED;
      if (fabs(g.p().xs) > 0.02 * GAME_SPEED * GAME_SPEED){
        g.p().xs -= g.p().xs/ fabs(g.p().xs) * 0.02 * GAME_SPEED * GAME_SPEED;
      }
      // Smoking plane
      g.p().crash++;
      if (g.p().crash == int(5/GAME_SPEED)){
        g.p().crash = 0;
        smoketype newsmoke;
        newsmoke.x = int(g.p().x);
        newsmoke.y = g.p().y;
        newsmoke.time = 0;
        g.smoke.add(newsmoke);
      }
      break;

    case 3: // Crashed planes
      g.p().crash++;
      if (g.p().crash == int(70/GAME_SPEED)){
        if (!g.p().drak){
          // Respawn plane to runway
          g.p().land = 0;
          g.p().state = 0;
          g.p().rotate = 0;
          g.p().crash = 0;
          g.p().x = g.base[g.p().side].planex;
          g.p().y = g.base[g.p().side].planey;
          g.p().d = g.base[g.p().side].planed;
          g.p().xs = 0;
          g.p().ys = 0;
          g.p().s = 0;
          g.p().ammo = g.p().maxammo;
          g.p().bombs = g.p().maxbombs;
          g.p().coms = 0;
          g.p().targetx = 0;
          g.p().targety = 0;
          g.p().cruiseheight = 0;
        }else{
          // Expunge drak
          g.p().state = 4;
        }
      }
      break;

    case 4: // Expunged drak fighter (NB: shouldn't get here!)
      break;
 

  }
  // Move the planes
  g.p().x += g.p().xs;
  g.p().y += g.p().ys;

  // Control Engine Volume
  if ((g.p().control) > 0){
    if ((g.p().state == 0) && (g.p().land > 0)){
      double volume = g.p().s / (6.0*GAME_SPEED);
      g.sound.volume(g.p().control-1, volume * 0.5);
      if ((g.p().boost) && (g.p().enginesample == SOUND_JET)){
        g.p().enginesample = SOUND_BURNER;
        g.sound.loop(g.p().control-1,SOUND_BURNER);
      }
      if ((!g.p().boost) && (g.p().enginesample == SOUND_BURNER)){
        g.p().enginesample = SOUND_JET;
        g.sound.loop(g.p().control-1,SOUND_JET);
      }
    }else{
      g.sound.stop(g.p().control-1);
    }
  }

  if (g.p().state < 3) detect_collisions(g);

}