/** Squash karts or items that are around the end position (determined using * a joint) of the swatter. */ void Swatter::squashThingsAround() { const KartProperties* kp = m_kart->getKartProperties(); // Square of the minimum distance float min_dist2 = kp->getSwatterDistance2(); const World* world = World::getWorld(); // Get the node corresponding to the joint at the center of the swatter // (by swatter, I mean the thing hold in the hand, not the whole thing) scene::ISceneNode* swatter_node = m_scene_node->getJointNode("Swatter"); assert(swatter_node); Vec3 swatter_pos = swatter_node->getAbsolutePosition(); m_swat_sound->setPosition(swatter_pos); m_swat_sound->play(); // Squash karts around for(unsigned int i=0; i<world->getNumKarts(); i++) { AbstractKart *kart = world->getKart(i); // TODO: isSwatterReady() if(kart->isEliminated() || kart==m_kart) continue; // don't swat an already hurt kart if (kart->isInvulnerable() || kart->isSquashed()) continue; float dist2 = (kart->getXYZ()-swatter_pos).length2(); if(dist2 >= min_dist2) continue; // too far away, ignore this kart kart->setSquash(kp->getSquashDuration() * kart->getPlayerDifficulty()->getSquashDuration(), kp->getSquashSlowdown() * kart->getPlayerDifficulty()->getSquashSlowdown()); if (kart->getAttachment()->getType()==Attachment::ATTACH_BOMB) { // make bomb explode kart->getAttachment()->update(10000); HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion", "explosion.xml"); if(m_kart->getController()->isPlayerController()) he->setPlayerKartHit(); projectile_manager->addHitEffect(he); ExplosionAnimation::create(kart); } // if kart has bomb attached World::getWorld()->kartHit(kart->getWorldKartId()); } // for i < num_kartrs // TODO: squash items } // squashThingsAround
//----------------------------------------------------------------------------- void Attachment::update(float dt) { if(m_type==ATTACH_NOTHING) return; m_time_left -=dt; bool is_shield = (m_type == ATTACH_BUBBLEGUM_SHIELD|| m_type == ATTACH_NOLOK_BUBBLEGUM_SHIELD); float m_wanted_node_scale = is_shield ? std::max(1.0f, m_kart->getHighestPoint()*1.1f) : 1.0f; if (m_node_scale < m_wanted_node_scale) { m_node_scale += dt*1.5f; if (m_node_scale > m_wanted_node_scale) m_node_scale = m_wanted_node_scale; m_node->setScale(core::vector3df(m_node_scale,m_node_scale,m_node_scale)); } if(m_plugin) { bool discard = m_plugin->updateAndTestFinished(dt); if(discard) { clear(); // also removes the plugin return; } } switch (m_type) { case ATTACH_PARACHUTE: { // Partly handled in Kart::updatePhysics // Otherwise: disable if a certain percantage of // initial speed was lost // This percentage is based on the ratio of // initial_speed / initial_max_speed float f = m_initial_speed / stk_config->m_parachute_max_speed; if (f > 1.0f) f = 1.0f; // cap fraction if (m_kart->getSpeed() <= m_initial_speed * (stk_config->m_parachute_lbound_fraction + f * ( stk_config->m_parachute_ubound_fraction - stk_config->m_parachute_lbound_fraction))) { m_time_left = -1; } } break; case ATTACH_ANVIL: // handled in Kart::updatePhysics case ATTACH_NOTHING: // Nothing to do, but complete all cases for switch case ATTACH_MAX: break; case ATTACH_SWATTER: case ATTACH_NOLOKS_SWATTER: // Everything is done in the plugin. break; case ATTACH_BOMB: if (m_bomb_sound) m_bomb_sound->position(m_kart->getXYZ()); // Mesh animation frames are 1 to 61 frames (60 steps) // The idea is change second by second, counterclockwise 60 to 0 secs // If longer times needed, it should be a surprise "oh! bomb activated!" if(m_time_left <= (m_node->getEndFrame() - m_node->getStartFrame()-1)) { m_node->setCurrentFrame(m_node->getEndFrame() - m_node->getStartFrame()-1-m_time_left); } if(m_time_left<=0.0) { HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion", "explosion_bomb.xml"); if(m_kart->getController()->isPlayerController()) he->setPlayerKartHit(); projectile_manager->addHitEffect(he); ExplosionAnimation::create(m_kart); if (m_bomb_sound) { m_bomb_sound->stop(); sfx_manager->deleteSFX(m_bomb_sound); m_bomb_sound = NULL; } } break; case ATTACH_TINYTUX: // Nothing to do for tinytux, this is all handled in EmergencyAnimation break; case ATTACH_BUBBLEGUM_SHIELD: case ATTACH_NOLOK_BUBBLEGUM_SHIELD: if (m_time_left < 0) { m_time_left = 0.0f; if (m_bubble_explode_sound) sfx_manager->deleteSFX(m_bubble_explode_sound); m_bubble_explode_sound = sfx_manager->createSoundSource("bubblegum_explode"); m_bubble_explode_sound->position(m_kart->getXYZ()); m_bubble_explode_sound->play(); // drop a small bubble gum Vec3 hit_point; Vec3 normal; const Material* material_hit; Vec3 pos = m_kart->getXYZ(); Vec3 to=pos+Vec3(0, -10000, 0); World* world = World::getWorld(); world->getTrack()->getTriangleMesh().castRay(pos, to, &hit_point, &material_hit, &normal); // This can happen if the kart is 'over nothing' when dropping // the bubble gum if(material_hit) { normal.normalize(); pos.setY(hit_point.getY()-0.05f); ItemManager::get()->newItem(Item::ITEM_BUBBLEGUM, pos, normal, m_kart); } } break; } // switch // Detach attachment if its time is up. if ( m_time_left <= 0.0f) clear(); } // update
/** Randomly selects the new attachment. For a server process, the * attachment can be passed into this function. * \param item The item that was collected. * \param new_attachment Optional: only used on the clients, it * specifies the new attachment to use */ void Attachment::hitBanana(Item *item, int new_attachment) { const StateManager::ActivePlayer *const ap = m_kart->getController() ->getPlayer(); if(ap && ap->getConstProfile()==PlayerManager::getCurrentPlayer()) PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_BANANA, "banana",1 ); //Bubble gum shield effect: if(m_type == ATTACH_BUBBLEGUM_SHIELD || m_type == ATTACH_NOLOK_BUBBLEGUM_SHIELD) { m_time_left = 0.0f; return; } float leftover_time = 0.0f; bool add_a_new_item = true; if (dynamic_cast<ThreeStrikesBattle*>(World::getWorld()) != NULL) { World::getWorld()->kartHit(m_kart->getWorldKartId()); ExplosionAnimation::create(m_kart); return; } switch(getType()) // If there already is an attachment, make it worse :) { case ATTACH_BOMB: { add_a_new_item = false; HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion", "explosion_bomb.xml"); if(m_kart->getController()->isPlayerController()) he->setPlayerKartHit(); projectile_manager->addHitEffect(he); ExplosionAnimation::create(m_kart); clear(); if(new_attachment==-1) new_attachment = m_random.get(3); // Disable the banana on which the kart just is for more than the // default time. This is necessary to avoid that a kart lands on the // same banana again once the explosion animation is finished, giving // the kart the same penalty twice. float f = std::max(item->getDisableTime(), m_kart->getKartProperties()->getExplosionTime()+2.0f); item->setDisableTime(f); break; } case ATTACH_ANVIL: // if the kart already has an anvil, attach a new anvil, // and increase the overall time new_attachment = 2; leftover_time = m_time_left; break; case ATTACH_PARACHUTE: new_attachment = 2; leftover_time = m_time_left; break; default: // There is no attachment currently, but there will be one // so play the character sound ("Uh-Oh") m_kart->playCustomSFX(SFXManager::CUSTOM_ATTACH); if(new_attachment==-1) new_attachment = m_random.get(3); } // switch if (add_a_new_item) { switch (new_attachment) { case 0: set( ATTACH_PARACHUTE,stk_config->m_parachute_time+leftover_time); m_initial_speed = m_kart->getSpeed(); // if going very slowly or backwards, // braking won't remove parachute if(m_initial_speed <= 1.5) m_initial_speed = 1.5; break ; case 1: set( ATTACH_BOMB, stk_config->m_bomb_time+leftover_time); // if ( m_kart == m_kart[0] ) // sound -> playSfx ( SOUND_SHOOMF ) ; break ; case 2: set( ATTACH_ANVIL, stk_config->m_anvil_time+leftover_time); // if ( m_kart == m_kart[0] ) // sound -> playSfx ( SOUND_SHOOMF ) ; // Reduce speed once (see description above), all other changes are // handled in Kart::updatePhysics m_kart->adjustSpeed(stk_config->m_anvil_speed_factor); m_kart->updateWeight(); break ; } // switch } } // hitBanana
//----------------------------------------------------------------------------- void Attachment::update(float dt) { if(m_type==ATTACH_NOTHING) return; m_time_left -=dt; if(m_plugin) { bool discard = m_plugin->updateAndTestFinished(dt); if(discard) { clear(); // also removes the plugin return; } } switch (m_type) { case ATTACH_PARACHUTE: // Partly handled in Kart::updatePhysics // Otherwise: disable if a certain percantage of // initial speed was lost if(m_kart->getSpeed() <= m_initial_speed*stk_config->m_parachute_done_fraction) { m_time_left = -1; } break; case ATTACH_ANVIL: // handled in Kart::updatePhysics case ATTACH_NOTHING: // Nothing to do, but complete all cases for switch case ATTACH_MAX: break; case ATTACH_SWATTER: case ATTACH_NOLOKS_SWATTER: // Everything is done in the plugin. break; case ATTACH_BOMB: if (m_bomb_sound) m_bomb_sound->position(m_kart->getXYZ()); // Mesh animation frames are 1 to 61 frames (60 steps) // The idea is change second by second, counterclockwise 60 to 0 secs // If longer times needed, it should be a surprise "oh! bomb activated!" if(m_time_left <= (m_node->getEndFrame() - m_node->getStartFrame()-1)) { m_node->setCurrentFrame(m_node->getEndFrame() - m_node->getStartFrame()-1-m_time_left); } if(m_time_left<=0.0) { HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion"); if(m_kart->getController()->isPlayerController()) he->setPlayerKartHit(); projectile_manager->addHitEffect(he); ExplosionAnimation::create(m_kart); if (m_bomb_sound) { m_bomb_sound->stop(); sfx_manager->deleteSFX(m_bomb_sound); m_bomb_sound = NULL; } } break; case ATTACH_TINYTUX: // Nothing to do for tinytux, this is all handled in EmergencyAnimation break; } // switch // Detach attachment if its time is up. if ( m_time_left <= 0.0f) clear(); } // update