int GameLevelScript::RespawnPlayer( CLuaVirtualMachine& vm ) { lua_State* state = static_cast<lua_State*>( vm ); const std::string respawnId = lua_tostring( state, -1 ); const int currentStateId = GameState::GetStateID(); if( currentStateId == GameState::k_state_gameplay ) { GS_GamePlay* gameplay = static_cast<GS_GamePlay*>( GameState::GetCurrentState() ); if( gameplay ) { GameLevel* gamelevel = gameplay->GetGameLevel(); if( gamelevel ) { Player* player = gamelevel->GetPlayer(); if( player ) { player->Respawn( respawnId ); } } } } return 0; }
void Submarine::draw(GameLevel& context) const { if(armor == 0 || (extraLives >= 0 && context.frameCount() / 3 % 2 == 0)) { context.core.drawBitmap(fieldX() - 1, fieldY() - 2, bitmapSubmarine, 2); if(context.frameCount() % ECHO_CYCLE > 30) { // sustain: 30 frames context.core.drawPixel(fieldX() + 6, fieldY() - 1, 1); } } //context.getArduboy().drawRect(x, y, W, H, 0); }
void Generator::draw(GameLevel& context) const { if(dispTimer > 0 && context.frameCount() / 5 % 2 == 0) { char text[12]; sprintf(text, "Score %05d", context.getScore()); context.core.setCursor(SCREEN_WIDTH / 2 - 6 * 11 / 2, 0); context.core.print(text); sprintf(text, "ZONE%3d", zone); context.core.setCursor(SCREEN_WIDTH / 2 - 6 * 7 / 2, 10); context.core.print(text); } }
GameLevel* Game::CreateGameLevel( const int modeID, const int levelID ) { Physics* physics = Physics::GetInstance(); physics->Init(); GameLevel* gameLevel = new GameLevel( modeID, levelID ); gameLevel->Init(); physics->FreeInstance(); return gameLevel; }
void Game::InitGame() { winPositions[0] = (GLfloat)this->Width; winPositions[1] = (GLfloat)this->Width; Text = new TextRenderer(this->Width, this->Height); Text->Load("QuickJerk/DUNEBUG.ttf", 20); SoundEngine->play2D("audio/windy.mp3", GL_TRUE); ResourceMaster::LoadShader("SpriteShader.vert", "SpriteShader.frag", nullptr, "sprite"); ResourceMaster::LoadShader("ParticleShader.vert", "ParticleShader.frag", nullptr, "particle"); ResourceMaster::LoadShader("PostProcess.vert", "PostProcess.frag", nullptr, "postproc"); glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(this->Width), static_cast<GLfloat>(this->Height), 0.0f, -1.0f, 1.0f); ResourceMaster::GetShader("sprite").Use().SetInteger("image", 0); ResourceMaster::GetShader("sprite").SetMatrix4("projection", projection); ResourceMaster::GetShader("particle").Use().SetInteger("image", 0); ResourceMaster::GetShader("particle").SetMatrix4("projection", projection); Renderer = new SpriteRenderer(ResourceMaster::GetShader("sprite")); ResourceMaster::LoadTexture("Sprites/particle.png", GL_TRUE, "particle"); ResourceMaster::LoadTexture("Sprites/SquidPaddle.png", GL_TRUE, "squidPaddle", 5); ResourceMaster::LoadTexture("Sprites/DeadSquid.png", GL_TRUE, "deadSquid", 12); ResourceMaster::LoadTexture("Sprites/background.png", GL_TRUE, "background"); ResourceMaster::LoadTexture("Sprites/Blocks/plain.png", GL_FALSE, "plain"); ResourceMaster::LoadTexture("Sprites/Blocks/indestructible.png", GL_FALSE, "indestructible"); ResourceMaster::LoadTexture("Sprites/Blocks/chaos.png", GL_FALSE, "chaos"); ResourceMaster::LoadTexture("Sprites/Blocks/dizzy.png", GL_FALSE, "dizzy"); ResourceMaster::LoadTexture("Sprites/Blocks/invert.png", GL_FALSE, "invert"); ResourceMaster::LoadTexture("Sprites/Blocks/magnet.png", GL_FALSE, "magnet"); ResourceMaster::LoadTexture("Sprites/EyeBraun/globe.png", GL_TRUE, "globe"); ResourceMaster::LoadTexture("Sprites/EyeBraun/veins.png", GL_TRUE, "veins"); ResourceMaster::LoadTexture("Sprites/EyeBraun/iris.png", GL_TRUE, "iris"); ResourceMaster::LoadTexture("Sprites/EyeBraun/pupil.png", GL_TRUE, "pupil"); ResourceMaster::LoadTexture("Sprites/Blocks/speed.png", GL_TRUE, "speed"); ResourceMaster::LoadTexture("Sprites/Blocks/slow.png", GL_TRUE, "slow"); ResourceMaster::LoadTexture("Sprites/Blocks/extend.png", GL_TRUE, "extend"); ResourceMaster::LoadTexture("Sprites/Blocks/baby.png", GL_TRUE, "baby", 9); ResourceMaster::LoadTexture("Sprites/Blocks/death.png", GL_TRUE, "death"); Particles = new ParticleGenerator(ResourceMaster::GetShader("particle"), ResourceMaster::GetTexture("particle"), 500); Effects = new PostProcessor(ResourceMaster::GetShader("postproc"), this->Width, this->Height); glm::vec2 playerPos = glm::vec2( this->Width / 2 - PLAYER_SIZE.x / 2, this->Height - PLAYER_SIZE.y ); Player = new GameObject(playerPos, PLAYER_SIZE, ResourceMaster::GetTexture("squidPaddle")); glm::vec2 ballPos = playerPos + glm::vec2(PLAYER_SIZE.x / 2 - BALL_RADIUS, -BALL_RADIUS * 2); GameBall = new Ball(ballPos, BALL_RADIUS, INITIAL_BALL_VELOCITY, ResourceMaster::GetTexture("globe")); GameLevel one; one.Load("Levels/LevelOne.txt", this->Width, (GLuint)(this->Height * 0.5f)); this->Levels.push_back(one); this->Level = 0; }
void Submarine::onHit(GameLevel& context) { if(armor <= 0) { if(extraLives >= 0) { context.spawnParticle(fieldX() - 2, fieldY() - 4, PARTICLE_EXPLOSION); context.core.tone(185, 250); } --extraLives; if(extraLives < 0) { context.setGameover(); // ToDo: add gameover sfx inactivate(); } armor = ARMOR_FRAMES; } }
void SmallEnemy::onHit(GameLevel& context) { context.addScore(1); if(x < SCREEN_WIDTH + 20) { // near context.spawnParticle(round(x) - 5, round(y) - 4, PARTICLE_EXPLOSION); context.core.tone(880, 62); } // platoon elimination if(context.platoons.checkBonus(getPlatoon(), true)) { if(x < SCREEN_WIDTH + 20) { // near context.spawnParticle(round(x) - 2, round(y) - 2, PARTICLE_TEN_POINT); } context.addScore(10); } inactivate(); }
void Platoons::spawn(GameLevel& context) { const byte INTERVALS[] = {10, 16, 16}; for(byte i = 0; i < PLATOON_MAX; ++i) { if(!inUse(i)) { continue; } if( timers[i] % INTERVALS[types[i]] == 0 && timers[i] < PLATOON_CONSISTS * INTERVALS[types[i]] // limitation PLATOON_CONSISTS ) { // type const byte isOdd = timers[i] / INTERVALS[types[i]] % 2 == 1; // 0123 -> 1234 byte spawnType; if(types[i] == PLATOON_ZIG_FILE) { spawnType = isOdd ? SENEMY_ZIG_FIRE : SENEMY_ZIG_NOFIRE; } else { spawnType = isOdd ? SENEMY_TRI_FIRE : SENEMY_TRI_NOFIRE; } // y char y = spawnYs[i]; if(types[i] == PLATOON_TRI_SHOAL) { y += random(20) - 10; } // spawn if(context.spawnSmallEnemy(y, (i << 4) | spawnType)) { status[i] = 0; // reset platoon } } if(timers[i] < 0xff) { ++timers[i]; } } }
// 初始化游戏 void Game::Init() { // 加载相关着色器 ResourceManager::LoadShader("shaders/spriteVertexShader.glsl", "shaders/spriteFragmentShader.glsl", nullptr, "sprite"); ResourceManager::LoadShader("shaders/particleVertexShader.glsl", "shaders/particleFragmentShader.glsl", nullptr, "particle"); ResourceManager::LoadShader("shaders/vertexShader.glsl", "shaders/fragmentShader.glsl", nullptr, "postprocessing"); ResourceManager::LoadShader("shaders/textVertexShader.glsl", "shaders/textFragmentShader.glsl", nullptr, "text"); // 设置相关着色器 glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(this->Width), static_cast<GLfloat>(this->Height), 0.0f, -1.0f, 1.0f); ResourceManager::GetShader("sprite").Use().SetInteger("sprite", 0); ResourceManager::GetShader("sprite").SetMatrix4("projection", projection); ResourceManager::GetShader("particle").Use().SetInteger("sprite", 0); ResourceManager::GetShader("particle").SetMatrix4("projection", projection); // 加载相关纹理 ResourceManager::LoadTexture("textures/background.jpg", GL_TRUE, "background"); ResourceManager::LoadTexture("textures/awesomeface.png", GL_TRUE, "face"); ResourceManager::LoadTexture("textures/block.png", GL_TRUE, "block"); ResourceManager::LoadTexture("textures/block_solid.png", GL_TRUE, "block_solid"); ResourceManager::LoadTexture("textures/paddle.png", GL_TRUE, "paddle"); ResourceManager::LoadTexture("textures/particle.png", GL_TRUE, "particle"); ResourceManager::LoadTexture("textures/powerup_speed.png", GL_TRUE, "powerup_speed"); ResourceManager::LoadTexture("textures/powerup_sticky.png", GL_TRUE, "powerup_sticky"); ResourceManager::LoadTexture("textures/powerup_increase.png", GL_TRUE, "powerup_increase"); ResourceManager::LoadTexture("textures/powerup_confuse.png", GL_TRUE, "powerup_confuse"); ResourceManager::LoadTexture("textures/powerup_chaos.png", GL_TRUE, "powerup_chaos"); ResourceManager::LoadTexture("textures/powerup_passthrough.png", GL_TRUE, "powerup_passthrough"); // 根据着色器设置相应的渲染 Renderer = new SpriteRenderer(ResourceManager::GetShader("sprite")); Particles = new ParticleGenerator(ResourceManager::GetShader("particle"), ResourceManager::GetTexture("particle"), 500); Effects = new PostProcessor(ResourceManager::GetShader("postprocessing"), this->Width, this->Height); Text = new TextRenderer(ResourceManager::GetShader("text"), this->Width, this->Height); Text->Load("fonts/arial.ttf", 24); // 加载游戏的不同难度 GameLevel one; one.Load("levels/one.lvl", this->Width, this->Height * 0.5); GameLevel two; two.Load("levels/two.lvl", this->Width, this->Height * 0.5); GameLevel three; three.Load("levels/three.lvl", this->Width, this->Height * 0.5); GameLevel four; four.Load("levels/four.lvl", this->Width, this->Height * 0.5); this->Levels.push_back(one); this->Levels.push_back(two); this->Levels.push_back(three); this->Levels.push_back(four); this->Level = 0; // 设置游戏对象 glm::vec2 playerPos = glm::vec2(this->Width / 2 - PLAYER_SIZE.x / 2, this->Height - PLAYER_SIZE.y); Player = new GameObject(playerPos, PLAYER_SIZE, ResourceManager::GetTexture("paddle")); glm::vec2 ballPos = playerPos + glm::vec2(PLAYER_SIZE.x / 2 - BALL_RADIUS, -BALL_RADIUS * 2); Ball = new BallObject(ballPos, BALL_RADIUS, INITIAL_BALL_VELOCITY, ResourceManager::GetTexture("face")); // 背景音乐 BackgroudMusic->play2D("audio/breakout.mp3", GL_TRUE); }
void Game::Init() { // Load shaders ResourceManager::LoadShader("src/Shader/shader_vertex.vert", "src/Shader/shader_fragment.frag", nullptr, "sprite"); ResourceManager::LoadShader("src/Shader/particle.vert", "src/Shader/particle.frag", nullptr, "particle"); ResourceManager::LoadShader("src/Shader/post_processing.vs", "src/Shader/post_processing.frag", nullptr, "postprocessing"); // Configure shaders glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(this->Width), static_cast<GLfloat>(this->Height), 0.0f, -1.0f, 1.0f); ResourceManager::GetShader("sprite").Use().SetInteger("image", 0); ResourceManager::GetShader("sprite").SetMatrix4("projection", projection); ResourceManager::GetShader("particle").Use().SetInteger("sprite", 0); ResourceManager::GetShader("particle").SetMatrix4("projection", projection); // Load textures ResourceManager::LoadTexture("src/Textures/background.jpg", GL_FALSE, "background"); ResourceManager::LoadTexture("src/Textures/awesomeface.png", GL_TRUE, "face"); ResourceManager::LoadTexture("src/Textures/block.png", GL_FALSE, "block"); ResourceManager::LoadTexture("src/Textures/block_solid.png", GL_FALSE, "block_solid"); ResourceManager::LoadTexture("src/Textures/paddle.png", GL_TRUE , "paddle"); ResourceManager::LoadTexture("src/Textures/particle.png", GL_TRUE, "particle"); ResourceManager::LoadTexture("src/Textures/powerup_speed.png", GL_TRUE, "powerup_speed"); ResourceManager::LoadTexture("src/Textures/powerup_sticky.png", GL_TRUE, "powerup_sticky"); ResourceManager::LoadTexture("src/Textures/powerup_increase.png", GL_TRUE, "powerup_increase"); ResourceManager::LoadTexture("src/Textures/powerup_confuse.png", GL_TRUE, "powerup_confuse"); ResourceManager::LoadTexture("src/Textures/powerup_chaos.png", GL_TRUE, "powerup_chaos"); ResourceManager::LoadTexture("src/Textures/powerup_passthrough.png", GL_TRUE, "powerup_passthrough"); Renderer = new SpriteRenderer(ResourceManager::GetShader("sprite")); Particles = new ParticleGenerator(ResourceManager::GetShader("particle"), ResourceManager::GetTexture("particle"), 500); Effects = new PostProcessor(ResourceManager::GetShader("postprocessing"), this->Width, this->Height); Text = new TextRenderer(this->Width, this->Height); Text->Load("src/Fonts/OCRAEXT.TTF", 24); // Load levels GameLevel one; one.Load("src/Level/one.lvl", this->Width, this->Height * 0.5); GameLevel two; two.Load("src/Level/two.lvl", this->Width, this->Height * 0.5); GameLevel three; three.Load("src/Level/three.lvl", this->Width, this->Height * 0.5); GameLevel four; four.Load("src/Level/four.lvl", this->Width, this->Height * 0.5); this->Levels.push_back(one); this->Levels.push_back(two); this->Levels.push_back(three); this->Levels.push_back(four); this->Level = 0; // Configure game objects glm::vec2 playerPos = glm::vec2(this->Width / 2 - PLAYER_SIZE.x / 2, this->Height - PLAYER_SIZE.y); Player = new GameObject(playerPos, PLAYER_SIZE, ResourceManager::GetTexture("paddle")); glm::vec2 ballPos = playerPos + glm::vec2(PLAYER_SIZE.x / 2 - BALL_RADIUS, -BALL_RADIUS * 2); Ball = new BallObject(ballPos, BALL_RADIUS, INITIAL_BALL_VELOCITY, ResourceManager::GetTexture("face")); //Effects->Shake = GL_TRUE; //Effects->Confuse = GL_TRUE; //Effects->Chaos = GL_TRUE; SoundEngine->play2D("src/Audio/breakout.mp3", GL_TRUE); }
void Submarine::move(GameLevel& context) { if(context.isGameover()) { return; } // control static const int SPD = 1 << 7; static const int R2 = 90; // 0.5/sqrt(2) / (1/256) if(context.core.pressed(BTN_U) && context.core.pressed(BTN_L)) { x -= R2; y -= R2; } else if(context.core.pressed(BTN_U) && context.core.pressed(BTN_R)) { x += R2; y -= R2; } else if(context.core.pressed(BTN_D) && context.core.pressed(BTN_L)) { x -= R2; y += R2; } else if(context.core.pressed(BTN_D) && context.core.pressed(BTN_R)) { x += R2; y += R2; } else if(context.core.pressed(BTN_U)) { y -= SPD; } else if(context.core.pressed(BTN_L)) { x -= SPD; } else if(context.core.pressed(BTN_R)) { x += SPD; } else if(context.core.pressed(BTN_D)) { y += SPD; } // clamping into field static const fixed MARGIN = 6; x = Clamp(x, 0, (SCREEN_WIDTH - MARGIN) << 8); y = Clamp(y, (MARGIN - H) << 8, (SCREEN_HEIGHT - MARGIN) << 8); // launching torpedo if(extraLives >= 0 && (context.core.pushed(BTN_A) || context.core.pushed(BTN_B))) { context.launchTorpedo((int)fieldX() + 10, fieldY() + 1); } //firing auto shot #ifdef LOW_FLASH_MEMORY if(context.frameCount() % 5 == 0) { context.fireAutoShot(fieldX() + 3, fieldY() - 3); } #else if(context.lookForEnemy() && context.frameCount() % 5 == 0) { context.fireAutoShot(fieldX() + 3, fieldY() - 3); } #endif // updating armor timer if(armor > 0) { --armor; } }
void BigEnemy::onHit(GameLevel& context) { // add score context.addScore(10); if(x > SCREEN_WIDTH) { // far bonus context.addScore((x - SCREEN_WIDTH) * 10 / (FIELD_WIDTH - SCREEN_WIDTH)); } // near if(x < SCREEN_WIDTH + 20) { context.core.tone(1047, 250); context.spawnParticle(x + random(-2, 8), y + random(-4, 4), PARTICLE_EXPLOSION); context.spawnParticle(x + random( 8, 18), y + random(-4, 4), PARTICLE_EXPLOSION); #ifndef LOW_FLASH_MEMORY context.removeAllBullets(); context.core.setQuake(); #endif } // reset inactivate(); }
void Echo::reset(GameLevel& context, const byte subX) { if(context.frameCount() % ECHO_CYCLE == 0) { for(byte i = 0; i < ECHO_VERT_RESO; ++i) { intensities[i] = 0; } acceptFlag = true; } else { acceptFlag = false; } submarineX = subX; }
void Echo::draw(GameLevel& context) const { if( context.frameCount() / 3 % 2 == 0 || // tearing context.frameCount() % ECHO_CYCLE < ECHO_CYCLE / 2 // sustain: 30 frames ) { return; } for(byte i = 0; i < ECHO_VERT_RESO; ++i) { for(byte j = 0; j < intensities[i]; ++j) { context.core.fillRect(SCREEN_WIDTH - (j - 1) * ECHO_GRID_SIZE, i * ECHO_GRID_SIZE, ECHO_GRID_SIZE - 1, ECHO_GRID_SIZE - 1, 1); } } }
void Bullet::draw(GameLevel& context) const { // ToDo: async animation (if there are enough memories) const byte frame = context.frameCount() / 3 % 2; if(type % 2 == 0) { const byte* bitmaps[] = {bitmapMbullet0, bitmapMbullet1}; context.core.drawBitmap(fieldX() - bitmapMbullet0[0]/2, fieldY() - bitmapMbullet0[1]/2, bitmaps[frame], 2); } else { const byte* bitmaps[] = {bitmapSbullet0, bitmapSbullet1}; context.core.drawBitmap(fieldX() - bitmapSbullet0[0]/2, fieldY() - bitmapSbullet0[1]/2, bitmaps[frame], 2); } //arduboy.drawPixel(x, y, 0); }
void BigEnemy::move(GameLevel& context) { // moving if(grazed() && x > SCREEN_WIDTH - 5) { x += -3; // submarine found } else if(timer % 5 == 0) { // -0.2 --x; } // frame out if(x + bitmapCruEnemy0[0] < 0) { inactivate(); } // setting sonar reaction context.echo.add(x, y, y+H); // firing bullet if(x < SCREEN_WIDTH - W / 2) { if(!onScreen()) { timer = 0; // in order to sync fire cycle state |= ON_SCREEN_MASK; } const byte d = context.difficulty(); if(timer == 0 || (d >= 60 && timer == 40)) { // freq up when 60 and over const char bulletY = y + bitmapCruEnemy0[1] / 2; const char bulletSpeed = (d >= 80) ? BULLET_TYPE2_SPD : BULLET_TYPE0_SPD; const char bulletType = (d >= 80) ? 2 : 0; context.fireBullet(x, bulletY, context.getFutureSubmarineAngle(x, bulletY, bulletSpeed), bulletType); } } // updating timer static const byte PERIOD = 150; timer = (timer + 1) % PERIOD; }
void SmallEnemy::move(GameLevel& context) { const byte period = (getType() == 0) ? ZIG_PERIOD : TRI_PERIOD; switch(getType()) { // zigzag case 0: { // moving // x -= 1.5, y -= 0.5 if(timer % 2 == 0) { x -= 2; y += (timer / (ZIG_PERIOD / 4) % 2 == 0) ? 1 : -1; } else { --x; } // firing bullet const byte d = context.difficulty(); const byte typeCond = canFire() || (d >= 70 && d < 80) || d >= 100; // [70,80) or 100 if( timer == 80 && typeCond && // time / type x < SCREEN_WIDTH - W / 2 && // position d >= 20 // dont fire less than 20 ) { const byte bulletType = (d >= 80) ? 3 : 1; // rapid when 80 and over const float subAngle = context.getSubmarineAngle(x, y); context.fireBullet(x, y, subAngle, bulletType); // 3way if((d >= 50 && d < 70) || d >= 90) { context.fireBullet(x, y, subAngle - radians(10), 1); context.fireBullet(x, y, subAngle + radians(10), 1); } } } break; // triangle default: { // moving if(timer % 6 == 0) { --x; } const int half = period / 2; int tmp = half - timer % half; tmp = tmp*tmp / (half*half/4) - 1; if(tmp < 0) { tmp = 0; } x -= tmp; // firing bullet const bool timeCond = timer == 64 || (context.difficulty() >= 25 && timer == 32) || (context.difficulty() >= 75 && timer == 96); if( timeCond && canFire() && // time / type x < SCREEN_WIDTH && x > SCREEN_WIDTH / 2 && // position context.difficulty() >= 20 // difficulty ) { context.fireBullet(x, y, context.getSubmarineAngle(x, y), 1); } } break; } // frame out if(x + 12 < 0) { context.platoons.checkBonus(getPlatoon(), false); inactivate(); } // setting sonar reaction context.echo.add(x, y, y+H); // updating timer timer = (timer + 1) % period; }
void Generator::spawn(GameLevel& context) { #ifdef DEBUG if(context.core.pressed(BTN_B)) { if(context.core.pushed(BTN_U)) { difficulty += 10; } if(context.core.pushed(BTN_D)) { difficulty -= 10; } } #endif if(dispTimer > 0) { --dispTimer; } if(delayTimer > 0) { --delayTimer; return; } // if delaying, skip generating step const byte* waves[] = { // generating scripts #ifdef DEBUG waveTest, #else waveEmpty, // 0 #endif waveBeginner0, waveBeginner1, waveRandomLines, waveZigTop, waveZigBottom, // easy 1-5 waveTriTri, waveSandwich, waveCatapult, waveSuperPlatoon, // normal 6-9 waveBigWall, waveJamming, waveCamouflage0, waveCamouflage1, waveArrows // hard 10-14 }; static const byte DIFFICULTY_GROUP[] = {5, 4, 5}; //static const byte WAVE_PATTERN_MAX = 15; byte inst; // current instruction (or operand) inst = pgm_read_byte(waves[waveIndex] + progCount); // fetch while(inst != INST_END_WAVE && delayTimer <= 0) { // spawn if((inst & INST_SPAWN_MASK) != 0) { const byte type = inst & INST_TYPE_MASK; // get next operand ++progCount; inst = pgm_read_byte(waves[waveIndex] + progCount); const byte rand = inst & INST_RAND_MASK; if(rand == INST_RAND_ERROR) { break; } // invalid operand byte y = inst & INST_Y_MASK; if (rand == INST_RAND_WIDE ) { y = random(4, 57); } else if(rand == INST_RAND_NARROW) { y += random(10) - 5; } switch(type) { case SPAWN_BIG: context.spawnBigEnemy (y); break; case SPAWN_ZIG_SINGLE: context.spawnSmallEnemy(y-5, SENEMY_ZIG_FIRE ); break; case SPAWN_ZIG_FILE: context.platoons.set (y-5, PLATOON_ZIG_FILE ); break; case SPAWN_TRI_SINGLE: context.spawnSmallEnemy(y , SENEMY_TRI_FIRE ); break; case SPAWN_TRI_LINE: context.platoons.set (y , PLATOON_TRI_LINE ); break; case SPAWN_TRI_SHOAL: context.platoons.set (y , PLATOON_TRI_SHOAL); break; default: break; } } // delay else { delayTimer = inst; } // get next instruction ++progCount; inst = pgm_read_byte(waves[waveIndex] + progCount); } // next wave static const byte ZONE_DISP_FRAMES = 90; static const byte DIFFICULTY_INCR = 20; static const byte DIFFICULTY_DECR = 10; if(inst == INST_END_WAVE && delayTimer <= 0) { ++waveCount; progCount = 0; // difficulty limit byte randNum; byte randMin = 1; // except zero if(getDifficulty() < 10) { randNum = DIFFICULTY_GROUP[0]; } else if(getDifficulty() < 50) { randNum = DIFFICULTY_GROUP[0] + DIFFICULTY_GROUP[1]; } else if(getDifficulty() < 70) { randNum = DIFFICULTY_GROUP[0] + DIFFICULTY_GROUP[1] + DIFFICULTY_GROUP[2]; } else{ randNum = DIFFICULTY_GROUP[1] + DIFFICULTY_GROUP[2]; randMin += DIFFICULTY_GROUP[0]; } waveIndex = random(randNum) + randMin; // difficulty up if(difficulty < DIFFICULTY_CAP + DIFFICULTY_DECR) { difficulty += DIFFICULTY_INCR / WAVES_IN_ZONE; } // next zone if(waveCount >= WAVES_IN_ZONE) { waveCount = 0; dispTimer = ZONE_DISP_FRAMES; // disp zone and score ++zone; // difficulty down if(difficulty < DIFFICULTY_CAP + DIFFICULTY_DECR && zone > 1) { difficulty -= DIFFICULTY_DECR; } } } }