Added a very first version of a swatter (or inflatable hammer).
Details are in the wiki (http://supertuxkart.sourceforge.net/Items). Note that the model is _obviously_ a placeholder, and I used the icon for the bomb (which isn't used in game atm) for the swatter. I hope someone can provide a better model and icon. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@9011 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
39ec2ffd74
commit
da8ec214ce
BIN
data/models/swatter-icon.png
Normal file
BIN
data/models/swatter-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
data/models/swatter.b3d
Normal file
BIN
data/models/swatter.b3d
Normal file
Binary file not shown.
@ -14,6 +14,7 @@
|
||||
<item name="anchor" icon="anchor-icon.png"
|
||||
model="anchor.b3d" />
|
||||
<item name="switch" icon="swap-icon.png" />
|
||||
<item name="swatter" icon="swatter-icon.png" />
|
||||
<item name="parachute" icon="parachute-icon.png"
|
||||
model="parachute.b3d" />
|
||||
<item name="plunger" icon="plunger-icon.png"
|
||||
@ -36,19 +37,19 @@
|
||||
be quite rare, since otherwise the item might be used
|
||||
too often (compared with many items which will only
|
||||
affect a karts or two). -->
|
||||
<!-- bubble cake bowl zipper plunger switch para anvil -->
|
||||
<first w="25 5 15 5 10 10 0 0"
|
||||
w-multi=" 0 0 5 0 0 0 0 0" />
|
||||
<top33 w="30 30 30 30 30 10 30 0"
|
||||
w-multi=" 0 10 10 0 10 0 0 0" />
|
||||
<mid33 w="30 30 30 30 30 10 30 0"
|
||||
w-multi=" 0 20 20 20 20 0 0 0" />
|
||||
<end33 w=" 0 30 30 30 30 10 30 30"
|
||||
w-multi=" 0 30 30 30 30 0 0 0" />
|
||||
<last w=" 0 30 30 60 60 0 60 60"
|
||||
w-multi=" 0 30 30 60 60 0 0 0" />
|
||||
<battle w=" 0 30 60 0 0 10 0 0"
|
||||
w-multi=" 0 0 5 0 0 0 0 0" />
|
||||
<!-- bubble cake bowl zipper plunger switch glove para anvil -->
|
||||
<first w="25 5 15 5 10 10 10 0 0"
|
||||
w-multi=" 0 0 5 0 0 0 5 0 0" />
|
||||
<top33 w="30 30 30 30 30 10 30 30 0"
|
||||
w-multi=" 0 10 10 0 10 0 10 0 0" />
|
||||
<mid33 w="30 30 30 30 30 10 30 30 0"
|
||||
w-multi=" 0 20 20 20 20 0 0 20 0" />
|
||||
<end33 w=" 0 30 30 30 30 10 30 30 30"
|
||||
w-multi=" 0 30 30 30 30 0 30 0 0" />
|
||||
<last w=" 0 30 30 60 60 0 0 60 60"
|
||||
w-multi=" 0 30 30 60 60 0 0 0 0" />
|
||||
<battle w=" 0 30 60 0 0 10 0 30 0"
|
||||
w-multi=" 0 0 5 0 0 0 0 5 0" />
|
||||
|
||||
</powerup>
|
||||
|
||||
|
@ -145,13 +145,13 @@
|
||||
<nitro power-boost="3" consumption="1" small-container="1" big-container="3"
|
||||
max-speed-increase="5" duration="1" fade-out-time="2"/>
|
||||
|
||||
<!-- time is the time a zipper is active. force is the additional
|
||||
zipper force. speed-gain is the one time additional speed.
|
||||
max-speed-increase is the additional speed allowed on top
|
||||
of the kart-specific maximum kart speed. Fade-out time determines
|
||||
how long it takes for a zipper to fade out (after 'time'). -->
|
||||
<zipper time="3.5" force="250.0" speed-gain="4.5" max-speed-increase="15"
|
||||
fade-out-time="1.0" />
|
||||
<!-- time is the time a zipper is active. force is the additional
|
||||
zipper force. speed-gain is the one time additional speed.
|
||||
max-speed-increase is the additional speed allowed on top
|
||||
of the kart-specific maximum kart speed. Fade-out time determines
|
||||
how long it takes for a zipper to fade out (after 'time'). -->
|
||||
<zipper time="3.5" force="250.0" speed-gain="4.5" max-speed-increase="15"
|
||||
fade-out-time="1.0" />
|
||||
|
||||
<!-- Skidding: increase: multiplicative increase of skidding factor in each frame.
|
||||
decrease: multiplicative decrease of skidding factor in each frame.
|
||||
@ -176,6 +176,20 @@
|
||||
add-power="3" min-speed="10"
|
||||
max-speed-increase="5" duration="1" fade-out-time="2"/>
|
||||
|
||||
<!-- Kart-specific settings for the swatter:
|
||||
duration: how long can the swatter be readied.
|
||||
count: how often can it be used.
|
||||
distance: How close a kart must be before it can be hit.
|
||||
animation-time: How long it takes for the swatter to hit a target.
|
||||
item-animation-time: How long the swatter will swat when a
|
||||
projectile hits.
|
||||
squash-duration: How long a kart will remain squashed.
|
||||
squash-slowdown: percentage of max speed that a kart is
|
||||
restricted to. -->
|
||||
<swatter duration="10" count="2" distance="3" animation-time="0.2"
|
||||
item-animation-time="0.04" squash-duration="5"
|
||||
squash-slowdown="0.5"/>
|
||||
|
||||
<!-- min-speed-radius and max-speed-radius define the smallest turn
|
||||
radius at lowest speed (4.64 m at speed 0) and at high speed
|
||||
(13.5 m at speed 12 m/s). Maximum steering angles for speeds
|
||||
|
@ -115,7 +115,8 @@ void InputManager::handleStaticAction(int key, int value)
|
||||
break;
|
||||
}
|
||||
case KEY_F1:
|
||||
if (UserConfigParams::m_artist_debug_mode && world && race_manager->getNumPlayers() ==1 )
|
||||
if (UserConfigParams::m_artist_debug_mode && world &&
|
||||
race_manager->getNumPlayers() ==1 )
|
||||
{
|
||||
Kart* kart = world->getLocalPlayerKart(0);
|
||||
kart->setPowerup(PowerupManager::POWERUP_BUBBLEGUM, 10000);
|
||||
@ -127,42 +128,48 @@ void InputManager::handleStaticAction(int key, int value)
|
||||
}
|
||||
break;
|
||||
case KEY_F2:
|
||||
if (UserConfigParams::m_artist_debug_mode && world && race_manager->getNumPlayers() ==1 )
|
||||
if (UserConfigParams::m_artist_debug_mode && world &&
|
||||
race_manager->getNumPlayers() ==1 )
|
||||
{
|
||||
Kart* kart = world->getLocalPlayerKart(0);
|
||||
kart->setPowerup(PowerupManager::POWERUP_PLUNGER, 10000);
|
||||
}
|
||||
break;
|
||||
case KEY_F3:
|
||||
if (UserConfigParams::m_artist_debug_mode && world && race_manager->getNumPlayers() ==1 )
|
||||
if (UserConfigParams::m_artist_debug_mode && world &&
|
||||
race_manager->getNumPlayers() ==1 )
|
||||
{
|
||||
Kart* kart = world->getLocalPlayerKart(0);
|
||||
kart->setPowerup(PowerupManager::POWERUP_CAKE, 10000);
|
||||
}
|
||||
break;
|
||||
case KEY_F4:
|
||||
if (UserConfigParams::m_artist_debug_mode && world && race_manager->getNumPlayers() ==1 )
|
||||
if (UserConfigParams::m_artist_debug_mode && world &&
|
||||
race_manager->getNumPlayers() ==1 )
|
||||
{
|
||||
Kart* kart = world->getLocalPlayerKart(0);
|
||||
kart->setPowerup(PowerupManager::POWERUP_SWITCH, 10000);
|
||||
}
|
||||
break;
|
||||
case KEY_F5:
|
||||
if (UserConfigParams::m_artist_debug_mode && world && race_manager->getNumPlayers() ==1 )
|
||||
if (UserConfigParams::m_artist_debug_mode && world &&
|
||||
race_manager->getNumPlayers() ==1 )
|
||||
{
|
||||
Kart* kart = world->getLocalPlayerKart(0);
|
||||
kart->setPowerup(PowerupManager::POWERUP_BOWLING, 10000);
|
||||
}
|
||||
break;
|
||||
case KEY_F6:
|
||||
if (UserConfigParams::m_artist_debug_mode && world && race_manager->getNumPlayers() == 1)
|
||||
if (UserConfigParams::m_artist_debug_mode && world &&
|
||||
race_manager->getNumPlayers() == 1)
|
||||
{
|
||||
Kart* kart = world->getLocalPlayerKart(0);
|
||||
kart->setPowerup(PowerupManager::POWERUP_PARACHUTE, 10000);
|
||||
}
|
||||
break;
|
||||
case KEY_F7:
|
||||
if (UserConfigParams::m_artist_debug_mode && world && race_manager->getNumPlayers() == 1)
|
||||
if (UserConfigParams::m_artist_debug_mode && world &&
|
||||
race_manager->getNumPlayers() == 1)
|
||||
{
|
||||
Kart* kart = world->getLocalPlayerKart(0);
|
||||
kart->setPowerup(PowerupManager::POWERUP_ZIPPER, 10000);
|
||||
@ -180,7 +187,8 @@ void InputManager::handleStaticAction(int key, int value)
|
||||
const int count = World::getWorld()->getNumKarts();
|
||||
for (int n=0; n<count; n++)
|
||||
{
|
||||
World::getWorld()->getKart(n)->getNode()->setVisible(gui->m_enabled);
|
||||
World::getWorld()->getKart(n)->getNode()
|
||||
->setVisible(gui->m_enabled);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -191,8 +199,17 @@ void InputManager::handleStaticAction(int key, int value)
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_F9:
|
||||
if (UserConfigParams::m_artist_debug_mode && world &&
|
||||
race_manager->getNumPlayers() == 1)
|
||||
{
|
||||
Kart* kart = world->getLocalPlayerKart(0);
|
||||
kart->setPowerup(PowerupManager::POWERUP_SWATTER, 10000);
|
||||
}
|
||||
|
||||
case KEY_F11:
|
||||
if (UserConfigParams::m_artist_debug_mode && value && control_is_pressed)
|
||||
if (UserConfigParams::m_artist_debug_mode && value &&
|
||||
control_is_pressed)
|
||||
{
|
||||
if (world != NULL)
|
||||
{
|
||||
@ -203,17 +220,9 @@ void InputManager::handleStaticAction(int key, int value)
|
||||
|
||||
case KEY_F12:
|
||||
if(value)
|
||||
UserConfigParams::m_display_fps = !UserConfigParams::m_display_fps;
|
||||
UserConfigParams::m_display_fps =
|
||||
!UserConfigParams::m_display_fps;
|
||||
break;
|
||||
#ifndef WIN32
|
||||
// For now disable F9 toggling fullscreen, since windows requires
|
||||
// to reload all textures, display lists etc. Fullscreen can
|
||||
// be toggled from the main menu (options->display).
|
||||
case KEY_F9:
|
||||
// TODO; toggle fullscreen
|
||||
//irrDriver->toggleFullscreen(false); // 0: do not reset textures
|
||||
// Fall through to put the game into pause mode.
|
||||
#endif
|
||||
case KEY_F10:
|
||||
if(world) history->Save();
|
||||
break;
|
||||
@ -227,17 +236,20 @@ void InputManager::handleStaticAction(int key, int value)
|
||||
/**
|
||||
* Handles input when an input sensing mode (when configuring input)
|
||||
*/
|
||||
void InputManager::inputSensing(Input::InputType type, int deviceID, int button,
|
||||
Input::AxisDirection axisDirection, int value)
|
||||
void InputManager::inputSensing(Input::InputType type, int deviceID,
|
||||
int button, Input::AxisDirection axisDirection,
|
||||
int value)
|
||||
{
|
||||
#if INPUT_MODE_DEBUG
|
||||
std::cout << "INPUT SENSING... ";
|
||||
#endif
|
||||
|
||||
// don't store if we're trying to do something like bindings keyboard keys on a gamepad
|
||||
// don't store if we're trying to do something like bindings keyboard
|
||||
// keys on a gamepad
|
||||
if (m_mode == INPUT_SENSE_KEYBOARD && type != Input::IT_KEYBOARD)
|
||||
return;
|
||||
if (m_mode == INPUT_SENSE_GAMEPAD && type != Input::IT_STICKMOTION && type != Input::IT_STICKBUTTON)
|
||||
if (m_mode == INPUT_SENSE_GAMEPAD && type != Input::IT_STICKMOTION &&
|
||||
type != Input::IT_STICKBUTTON)
|
||||
return;
|
||||
|
||||
#if INPUT_MODE_DEBUG
|
||||
@ -282,7 +294,8 @@ void InputManager::inputSensing(Input::InputType type, int deviceID, int button,
|
||||
case Input::IT_STICKMOTION:
|
||||
{
|
||||
std::cout << "%% storing new axis binding, value=" << value <<
|
||||
" deviceID=" << deviceID << " button=" << button << " axisDirection=" <<
|
||||
" deviceID=" << deviceID << " button=" << button <<
|
||||
" axisDirection=" <<
|
||||
(axisDirection == Input::AD_NEGATIVE ? "-" : "+") << "\n";
|
||||
// We have to save the direction in which the axis was moved.
|
||||
// This is done by storing it as a sign (and since button can
|
||||
@ -343,8 +356,10 @@ void InputManager::inputSensing(Input::InputType type, int deviceID, int button,
|
||||
//-----------------------------------------------------------------------------
|
||||
int InputManager::getPlayerKeyboardID() const
|
||||
{
|
||||
// In no-assign mode, just return the GUI player ID (devices not assigned yet)
|
||||
if (m_device_manager->getAssignMode() == NO_ASSIGN) return PLAYER_ID_GAME_MASTER;
|
||||
// In no-assign mode, just return the GUI player ID (devices not
|
||||
// assigned yet)
|
||||
if (m_device_manager->getAssignMode() == NO_ASSIGN)
|
||||
return PLAYER_ID_GAME_MASTER;
|
||||
|
||||
// Otherwise, after devices are assigned, we can check in more depth
|
||||
// Return the first keyboard that is actually being used
|
||||
@ -373,7 +388,8 @@ int InputManager::getPlayerKeyboardID() const
|
||||
* Note: It is the obligation of the called menu to switch of the sense mode.
|
||||
*
|
||||
*/
|
||||
void InputManager::dispatchInput(Input::InputType type, int deviceID, int button,
|
||||
void InputManager::dispatchInput(Input::InputType type, int deviceID,
|
||||
int button,
|
||||
Input::AxisDirection axisDirection, int value)
|
||||
{
|
||||
// Act different in input sensing mode.
|
||||
@ -386,21 +402,28 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int button
|
||||
|
||||
StateManager::ActivePlayer* player = NULL;
|
||||
PlayerAction action;
|
||||
bool action_found = m_device_manager->translateInput( type, deviceID, button, axisDirection, value,
|
||||
m_mode, &player, &action);
|
||||
bool action_found = m_device_manager->translateInput(type, deviceID,
|
||||
button, axisDirection,
|
||||
value, m_mode,
|
||||
&player, &action);
|
||||
|
||||
// if didn't find a _menu_ action, try finding a corresponding game action as fallback
|
||||
// (the GUI can handle them too)
|
||||
// if didn't find a _menu_ action, try finding a corresponding game action
|
||||
// as fallback (the GUI can handle them too)
|
||||
if (!action_found && m_mode == MENU)
|
||||
{
|
||||
action_found = m_device_manager->translateInput(type, deviceID, button, axisDirection, value,
|
||||
INGAME, &player, &action);
|
||||
action_found = m_device_manager->translateInput(type, deviceID,
|
||||
button, axisDirection,
|
||||
value, INGAME, &player,
|
||||
&action);
|
||||
}
|
||||
|
||||
// in menus, some keyboard keys are standard (before each player selected his device)
|
||||
// So if a key could not be mapped to any known binding, fall back to check the defaults.
|
||||
if (!action_found && StateManager::get()->getGameState() != GUIEngine::GAME && type == Input::IT_KEYBOARD &&
|
||||
m_mode == MENU && m_device_manager->getAssignMode() == NO_ASSIGN)
|
||||
// in menus, some keyboard keys are standard (before each player selected
|
||||
// his device). So if a key could not be mapped to any known binding,
|
||||
// fall back to check the defaults.
|
||||
if (!action_found &&
|
||||
StateManager::get()->getGameState() != GUIEngine::GAME &&
|
||||
type == Input::IT_KEYBOARD &&
|
||||
m_mode == MENU && m_device_manager->getAssignMode() == NO_ASSIGN)
|
||||
{
|
||||
action = PA_BEFORE_FIRST;
|
||||
|
||||
@ -431,7 +454,8 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int button
|
||||
if (m_device_manager->getAssignMode() == DETECT_NEW)
|
||||
{
|
||||
// Player is unjoining
|
||||
if ((player != NULL) && (action == PA_RESCUE || action == PA_MENU_CANCEL))
|
||||
if ((player != NULL) && (action == PA_RESCUE ||
|
||||
action == PA_MENU_CANCEL ) )
|
||||
{
|
||||
// returns true if the event was handled
|
||||
if (KartSelectionScreen::getInstance()->playerQuit( player ))
|
||||
@ -457,25 +481,30 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int button
|
||||
InputDevice *device = NULL;
|
||||
if (type == Input::IT_KEYBOARD)
|
||||
{
|
||||
//std::cout << "==== New Player Joining with Key " << button << " ====" << std::endl;
|
||||
//std::cout << "==== New Player Joining with Key " <<
|
||||
// button << " ====" << std::endl;
|
||||
device = m_device_manager->getKeyboardFromBtnID(button);
|
||||
}
|
||||
else if (type == Input::IT_STICKBUTTON || type == Input::IT_STICKMOTION)
|
||||
else if (type == Input::IT_STICKBUTTON ||
|
||||
type == Input::IT_STICKMOTION )
|
||||
{
|
||||
device = m_device_manager->getGamePadFromIrrID(deviceID);
|
||||
}
|
||||
|
||||
if (device != NULL)
|
||||
{
|
||||
KartSelectionScreen::getInstance()->playerJoin( device, false );
|
||||
KartSelectionScreen::getInstance()->playerJoin(device,
|
||||
false );
|
||||
}
|
||||
}
|
||||
return; // we're done here, ignore devices that aren't associated with players
|
||||
return; // we're done here, ignore devices that aren't
|
||||
// associated with players
|
||||
}
|
||||
}
|
||||
|
||||
// ... when in-game
|
||||
if (StateManager::get()->getGameState() == GUIEngine::GAME && !GUIEngine::ModalDialog::isADialogActive())
|
||||
if (StateManager::get()->getGameState() == GUIEngine::GAME &&
|
||||
!GUIEngine::ModalDialog::isADialogActive() )
|
||||
{
|
||||
// Find the corresponding PlayerKart from our ActivePlayer instance
|
||||
Kart* pk;
|
||||
@ -490,7 +519,8 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int button
|
||||
|
||||
if (pk == NULL)
|
||||
{
|
||||
std::cerr << "Error, trying to process action for an unknown player\n";
|
||||
std::cerr <<
|
||||
"Error, trying to process action for an unknown player\n";
|
||||
return;
|
||||
}
|
||||
|
||||
@ -501,29 +531,31 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int button
|
||||
{
|
||||
|
||||
// reset timer when released
|
||||
if (abs(value) == 0 && (/*type == Input::IT_KEYBOARD ||*/ type == Input::IT_STICKBUTTON))
|
||||
if (abs(value) == 0 && type == Input::IT_STICKBUTTON)
|
||||
{
|
||||
//if(type == Input::IT_STICKBUTTON) std::cout << "resetting because type == Input::IT_STICKBUTTON\n";
|
||||
//else std::cout << "resetting for another reason\n";
|
||||
|
||||
m_timer_in_use = false;
|
||||
m_timer = 0;
|
||||
}
|
||||
|
||||
// When in master-only mode, we can safely assume that players are set up, contrarly to
|
||||
// early menus where we accept every input because players are not set-up yet
|
||||
// When in master-only mode, we can safely assume that players
|
||||
// are set up, contrarly to early menus where we accept every
|
||||
// input because players are not set-up yet
|
||||
if (m_master_player_only && player == NULL)
|
||||
{
|
||||
if (type == Input::IT_STICKMOTION || type == Input::IT_STICKBUTTON)
|
||||
if (type == Input::IT_STICKMOTION ||
|
||||
type == Input::IT_STICKBUTTON)
|
||||
{
|
||||
GamePadDevice* gp = getDeviceList()->getGamePadFromIrrID(deviceID);
|
||||
GamePadDevice* gp =
|
||||
getDeviceList()->getGamePadFromIrrID(deviceID);
|
||||
|
||||
if (gp != NULL &&
|
||||
abs(value)>gp->m_deadzone)
|
||||
{
|
||||
//I18N: message shown when an input device is used but is not associated to any player
|
||||
GUIEngine::showMessage(_("Ignoring '%s', you needed to join earlier to play!",
|
||||
irr::core::stringw(gp->m_name.c_str()).c_str()));
|
||||
//I18N: message shown when an input device is used but
|
||||
// is not associated to any player
|
||||
GUIEngine::showMessage(
|
||||
_("Ignoring '%s', you needed to join earlier to play!",
|
||||
irr::core::stringw(gp->m_name.c_str()).c_str()) );
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -538,27 +570,36 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int button
|
||||
m_timer = 0.25;
|
||||
}
|
||||
|
||||
// player may be NULL in early menus, before player setup has been performed
|
||||
// player may be NULL in early menus, before player setup has
|
||||
// been performed
|
||||
int playerID = (player == NULL ? 0 : player->getID());
|
||||
|
||||
// If only the master player can act, and this player is not the master, ignore his input
|
||||
if (m_device_manager->getAssignMode() == ASSIGN && m_master_player_only &&
|
||||
// If only the master player can act, and this player is not
|
||||
// the master, ignore his input
|
||||
if (m_device_manager->getAssignMode() == ASSIGN &&
|
||||
m_master_player_only &&
|
||||
playerID != PLAYER_ID_GAME_MASTER)
|
||||
{
|
||||
//I18N: message shown when a player that isn't game master tries to modify options that
|
||||
//I18N: only the game master is allowed to
|
||||
GUIEngine::showMessage(_("Only the Game Master may act at this point!"));
|
||||
//I18N: message shown when a player that isn't game master
|
||||
//I18N: tries to modify options that only the game master
|
||||
//I18N: is allowed to
|
||||
GUIEngine::showMessage(
|
||||
_("Only the Game Master may act at this point!"));
|
||||
return;
|
||||
}
|
||||
|
||||
// all is good, pass the translated input event on to the event handler
|
||||
GUIEngine::EventHandler::get()->processGUIAction(action, deviceID, abs(value), type, playerID);
|
||||
// all is good, pass the translated input event on to the
|
||||
// event handler
|
||||
GUIEngine::EventHandler::get()
|
||||
->processGUIAction(action, deviceID, abs(value), type,
|
||||
playerID);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == Input::IT_KEYBOARD)
|
||||
{
|
||||
// keyboard press not handled by device manager / bindings. Check static bindings...
|
||||
// keyboard press not handled by device manager / bindings.
|
||||
// Check static bindings...
|
||||
handleStaticAction( button, value );
|
||||
}
|
||||
} // input
|
||||
@ -568,14 +609,16 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int button
|
||||
void InputManager::setMasterPlayerOnly(bool enabled)
|
||||
{
|
||||
#if INPUT_MODE_DEBUG
|
||||
std::cout << "====== InputManager::setMasterPlayerOnly(" << enabled << ") ======\n";
|
||||
std::cout <<
|
||||
"====== InputManager::setMasterPlayerOnly(" << enabled << ") ======\n";
|
||||
#endif
|
||||
m_master_player_only = enabled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** Returns whether only the master player should be allowed to perform changes in menus */
|
||||
/** Returns whether only the master player should be allowed to perform changes
|
||||
* in menus */
|
||||
bool InputManager::masterPlayerOnly() const
|
||||
{
|
||||
return m_device_manager->getAssignMode() == ASSIGN && m_master_player_only;
|
||||
@ -598,8 +641,10 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
{
|
||||
if (event.EventType == EET_JOYSTICK_INPUT_EVENT)
|
||||
{
|
||||
// Axes - FIXME, instead of checking all of them, ask the bindings which ones to poll
|
||||
for (int axis_id=0; axis_id<SEvent::SJoystickEvent::NUMBER_OF_AXES ; axis_id++)
|
||||
// Axes - FIXME, instead of checking all of them, ask the bindings
|
||||
// which ones to poll
|
||||
for (int axis_id=0; axis_id<SEvent::SJoystickEvent::NUMBER_OF_AXES ;
|
||||
axis_id++)
|
||||
{
|
||||
int value = event.JoystickEvent.Axis[axis_id];
|
||||
|
||||
@ -609,27 +654,32 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
event.JoystickEvent.Joystick, axis_id, value);
|
||||
}
|
||||
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick, axis_id,
|
||||
Input::AD_NEUTRAL, value);
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick,
|
||||
axis_id, Input::AD_NEUTRAL, value);
|
||||
}
|
||||
|
||||
if (event.JoystickEvent.POV == 65535)
|
||||
{
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick, Input::HAT_H_ID, Input::AD_NEUTRAL,
|
||||
0);
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick, Input::HAT_V_ID, Input::AD_NEUTRAL,
|
||||
0);
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick,
|
||||
Input::HAT_H_ID, Input::AD_NEUTRAL, 0);
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick,
|
||||
Input::HAT_V_ID, Input::AD_NEUTRAL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// *0.017453925f is to convert degrees to radians
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick, Input::HAT_H_ID, Input::AD_NEUTRAL,
|
||||
(int)(cos(event.JoystickEvent.POV*0.017453925f/100.0f)*Input::MAX_VALUE));
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick, Input::HAT_V_ID, Input::AD_NEUTRAL,
|
||||
(int)(sin(event.JoystickEvent.POV*0.017453925f/100.0f)*Input::MAX_VALUE));
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick,
|
||||
Input::HAT_H_ID, Input::AD_NEUTRAL,
|
||||
(int)(cos(event.JoystickEvent.POV*0.017453925f/100.0f)
|
||||
*Input::MAX_VALUE));
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick,
|
||||
Input::HAT_V_ID, Input::AD_NEUTRAL,
|
||||
(int)(sin(event.JoystickEvent.POV*0.017453925f/100.0f)
|
||||
*Input::MAX_VALUE));
|
||||
}
|
||||
|
||||
GamePadDevice* gp = getDeviceList()->getGamePadFromIrrID(event.JoystickEvent.Joystick);
|
||||
GamePadDevice* gp =
|
||||
getDeviceList()->getGamePadFromIrrID(event.JoystickEvent.Joystick);
|
||||
|
||||
if (gp == NULL)
|
||||
{
|
||||
@ -642,14 +692,17 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
const bool isButtonPressed = event.JoystickEvent.IsButtonPressed(i);
|
||||
|
||||
// Only report button events when the state of the button changes
|
||||
if ((!gp->isButtonPressed(i) && isButtonPressed) || (gp->isButtonPressed(i) && !isButtonPressed))
|
||||
if ((!gp->isButtonPressed(i) && isButtonPressed) ||
|
||||
(gp->isButtonPressed(i) && !isButtonPressed) )
|
||||
{
|
||||
if (UserConfigParams::m_gamepad_debug)
|
||||
{
|
||||
printf("button %i, status=%i\n", i, isButtonPressed);
|
||||
}
|
||||
|
||||
dispatchInput(Input::IT_STICKBUTTON, event.JoystickEvent.Joystick, i, Input::AD_POSITIVE,
|
||||
dispatchInput(Input::IT_STICKBUTTON,
|
||||
event.JoystickEvent.Joystick, i,
|
||||
Input::AD_POSITIVE,
|
||||
isButtonPressed ? Input::MAX_VALUE : 0);
|
||||
}
|
||||
gp->setButtonPressed(i, isButtonPressed);
|
||||
@ -676,9 +729,10 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
StateManager::get()->escapePressed();
|
||||
return EVENT_BLOCK;
|
||||
}
|
||||
// 'backspace' in a text control must never be mapped, since user can be in a text
|
||||
// area trying to erase text (and if it's mapped to rescue that would dismiss the
|
||||
// dialog instead of erasing a single letter). Same for spacebar. Same for letters.
|
||||
// 'backspace' in a text control must never be mapped, since user
|
||||
// can be in a text area trying to erase text (and if it's mapped
|
||||
// to rescue that would dismiss the dialog instead of erasing a
|
||||
// single letter). Same for spacebar. Same for letters.
|
||||
if (GUIEngine::isWithinATextBox())
|
||||
{
|
||||
if (key == KEY_BACK || key == KEY_SPACE || key == KEY_SHIFT)
|
||||
@ -696,7 +750,8 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
dispatchInput(Input::IT_KEYBOARD, event.KeyInput.Char, key,
|
||||
Input::AD_POSITIVE, Input::MAX_VALUE);
|
||||
|
||||
// if this action took us into a text box, don't let event continue (FIXME not the cleanest solution)
|
||||
// if this action took us into a text box, don't let event continue
|
||||
// (FIXME not the cleanest solution)
|
||||
if (!wasInTextBox && GUIEngine::isWithinATextBox())
|
||||
{
|
||||
return EVENT_BLOCK;
|
||||
@ -705,9 +760,10 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
}
|
||||
else
|
||||
{
|
||||
// 'backspace' in a text control must never be mapped, since user can be in a text
|
||||
// area trying to erase text (and if it's mapped to rescue that would dismiss the
|
||||
// dialog instead of erasing a single letter). Same for spacebar. Same for letters.
|
||||
// 'backspace' in a text control must never be mapped, since user
|
||||
// can be in a text area trying to erase text (and if it's mapped
|
||||
// to rescue that would dismiss the dialog instead of erasing a
|
||||
// single letter). Same for spacebar. Same for letters.
|
||||
if (GUIEngine::isWithinATextBox())
|
||||
{
|
||||
if (key == KEY_BACK || key == KEY_SPACE || key == KEY_SHIFT)
|
||||
@ -745,16 +801,21 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
EMIE_RMOUSE_LEFT_UP Right mouse button was left up.
|
||||
EMIE_MMOUSE_LEFT_UP Middle mouse button was left up.
|
||||
EMIE_MOUSE_MOVED The mouse cursor changed its position.
|
||||
EMIE_MOUSE_WHEEL The mouse wheel was moved. Use Wheel value in event data to find out in what direction and how fast.
|
||||
EMIE_MOUSE_WHEEL The mouse wheel was moved. Use Wheel value in
|
||||
event data to find out in what direction and
|
||||
how fast.
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
// block events in all modes but initial menus (except in text boxes to allow typing,
|
||||
// and except in modal dialogs in-game)
|
||||
// FIXME: 1) that's awful logic 2) that's not what the code below does, events are never blocked in menus
|
||||
if (getDeviceList()->getAssignMode() != NO_ASSIGN && !GUIEngine::isWithinATextBox() &&
|
||||
(!GUIEngine::ModalDialog::isADialogActive() && StateManager::get()->getGameState() == GUIEngine::GAME))
|
||||
// block events in all modes but initial menus (except in text boxes to
|
||||
// allow typing, and except in modal dialogs in-game)
|
||||
// FIXME: 1) that's awful logic 2) that's not what the code below does,
|
||||
// events are never blocked in menus
|
||||
if (getDeviceList()->getAssignMode() != NO_ASSIGN &&
|
||||
!GUIEngine::isWithinATextBox() &&
|
||||
(!GUIEngine::ModalDialog::isADialogActive() &&
|
||||
StateManager::get()->getGameState() == GUIEngine::GAME))
|
||||
{
|
||||
return EVENT_BLOCK;
|
||||
}
|
||||
@ -837,9 +898,9 @@ void InputManager::setMode(InputDriverMode new_mode)
|
||||
m_sensed_input_high_gamepad.clear();
|
||||
m_sensed_input_high_kbd.clear();
|
||||
|
||||
// The order is deliberate just in case someone starts to make
|
||||
// STK multithreaded: m_sensed_input must not be 0 when
|
||||
// mode == INPUT_SENSE_PREFER_{AXIS,BUTTON}.
|
||||
// The order is deliberate just in case someone starts
|
||||
// to make STK multithreaded: m_sensed_input must not be
|
||||
// 0 when mode == INPUT_SENSE_PREFER_{AXIS,BUTTON}.
|
||||
m_mode = MENU;
|
||||
|
||||
break;
|
||||
@ -886,8 +947,8 @@ void InputManager::setMode(InputDriverMode new_mode)
|
||||
// We must be in menu mode now in order to switch.
|
||||
assert (m_mode == MENU);
|
||||
|
||||
// Reset the helper values for the relative mouse movement supresses to
|
||||
// the notification of them as an input.
|
||||
// Reset the helper values for the relative mouse movement
|
||||
// supresses to the notification of them as an input.
|
||||
m_mouse_val_x = m_mouse_val_y = 0;
|
||||
m_mode = new_mode;
|
||||
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "network/network_manager.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
|
||||
#define SWAT_ANGLE 22.0f
|
||||
|
||||
Attachment::Attachment(Kart* kart)
|
||||
{
|
||||
m_type = ATTACH_NOTHING;
|
||||
@ -40,8 +42,8 @@ Attachment::Attachment(Kart* kart)
|
||||
|
||||
// If we attach a NULL mesh, we get a NULL scene node back. So we
|
||||
// have to attach some kind of mesh, but make it invisible.
|
||||
m_node = irr_driver->addAnimatedMesh(
|
||||
attachment_manager->getMesh(ATTACH_BOMB));
|
||||
m_node = irr_driver->addAnimatedMesh(
|
||||
attachment_manager->getMesh(Attachment::ATTACH_BOMB));
|
||||
#ifdef DEBUG
|
||||
std::string debug_name = kart->getIdent()+" (attachment)";
|
||||
m_node->setName(debug_name.c_str());
|
||||
@ -58,11 +60,10 @@ Attachment::~Attachment()
|
||||
} // ~Attachment
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Attachment::set(attachmentType type, float time, Kart *current_kart)
|
||||
void Attachment::set(AttachmentType type, float time, Kart *current_kart)
|
||||
{
|
||||
clear();
|
||||
|
||||
|
||||
m_node->setMesh(attachment_manager->getMesh(type));
|
||||
|
||||
if (!UserConfigParams::m_graphical_effects)
|
||||
@ -71,9 +72,18 @@ void Attachment::set(attachmentType type, float time, Kart *current_kart)
|
||||
m_node->setCurrentFrame(0);
|
||||
}
|
||||
|
||||
m_type = type;
|
||||
m_time_left = time;
|
||||
m_previous_owner = current_kart;
|
||||
m_type = type;
|
||||
m_time_left = time;
|
||||
m_previous_owner = current_kart;
|
||||
m_node->setRotation(core::vector3df(0, 0, 0));
|
||||
m_count = m_type==ATTACH_SWATTER
|
||||
? m_kart->getKartProperties()->getSwatterCount()
|
||||
: 1;
|
||||
m_animation_timer = 0.0f;
|
||||
m_animation_phase = SWATTER_AIMING;
|
||||
m_rot_per_sec = core::vector3df(0,0,0);
|
||||
m_animation_target = NULL;
|
||||
|
||||
// A parachute can be attached as result of the usage of an item. In this
|
||||
// case we have to save the current kart speed so that it can be detached
|
||||
// by slowing down.
|
||||
@ -98,6 +108,7 @@ void Attachment::set(attachmentType type, float time, Kart *current_kart)
|
||||
void Attachment::clear()
|
||||
{
|
||||
m_type=ATTACH_NOTHING;
|
||||
|
||||
m_time_left=0.0;
|
||||
m_node->setVisible(false);
|
||||
|
||||
@ -108,6 +119,12 @@ void Attachment::clear()
|
||||
} // clear
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** 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)
|
||||
{
|
||||
float leftover_time = 0.0f;
|
||||
@ -228,6 +245,11 @@ void Attachment::update(float dt)
|
||||
case ATTACH_NOTHING: // Nothing to do, but complete all cases for switch
|
||||
case ATTACH_MAX:
|
||||
break;
|
||||
case ATTACH_SWATTER:
|
||||
updateSwatter(dt);
|
||||
// If the swatter is used up, trigger cleaning up
|
||||
if(m_count==0) m_time_left = -1.0f;
|
||||
break;
|
||||
case ATTACH_BOMB:
|
||||
if(m_time_left <= (m_node->getEndFrame() - m_node->getStartFrame() - 1))
|
||||
{
|
||||
@ -249,4 +271,183 @@ void Attachment::update(float dt)
|
||||
if ( m_time_left <= 0.0f)
|
||||
clear();
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates an armed swatter: it checks for any karts that are close enough
|
||||
* and not invulnerable, it swats the kart.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void Attachment::updateSwatter(float dt)
|
||||
{
|
||||
core::vector3df r = m_node->getRotation();
|
||||
r += m_rot_per_sec * dt;
|
||||
switch(m_animation_phase)
|
||||
{
|
||||
case SWATTER_AIMING:
|
||||
aimSwatter();
|
||||
break;
|
||||
case SWATTER_TO_KART:
|
||||
if(fabsf(r.Z)>=90)
|
||||
{
|
||||
checkForHitKart(r.Z>0);
|
||||
m_rot_per_sec *= -1.0f;
|
||||
m_animation_phase = SWATTER_BACK_FROM_KART;
|
||||
}
|
||||
break;
|
||||
case SWATTER_BACK_FROM_KART:
|
||||
if (r.Z>0)
|
||||
{
|
||||
r = core::vector3df(0,0,0);
|
||||
m_rot_per_sec = r;
|
||||
m_animation_phase = SWATTER_AIMING;
|
||||
m_animation_target = NULL;
|
||||
}
|
||||
break;
|
||||
case SWATTER_ITEM_1: // swatter going to the left
|
||||
if(r.Z>SWAT_ANGLE)
|
||||
{
|
||||
m_animation_phase = SWATTER_ITEM_2;
|
||||
m_rot_per_sec *= -1.0f;
|
||||
}
|
||||
break;
|
||||
case SWATTER_ITEM_2: // swatter going all the way to the right
|
||||
if(r.Z<-SWAT_ANGLE)
|
||||
{
|
||||
m_animation_phase = SWATTER_ITEM_3;
|
||||
m_rot_per_sec *= -1.0f;
|
||||
}
|
||||
break;
|
||||
case SWATTER_ITEM_3: // swatter going back to rest position.
|
||||
if(r.Z>0)
|
||||
{
|
||||
r = core::vector3df(0,0,0);
|
||||
m_rot_per_sec = r;
|
||||
m_animation_phase = SWATTER_AIMING;
|
||||
}
|
||||
break;
|
||||
} // switch m_animation_phase
|
||||
|
||||
m_node->setRotation(r);
|
||||
} // updateSwatter
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns true if the point xyz is to the left of the kart.
|
||||
* \param xyz Point to determine the direction
|
||||
*/
|
||||
bool Attachment::isLeftSideOfKart(const Vec3 &xyz)
|
||||
{
|
||||
Vec3 forw_vec = m_kart->getTrans().getBasis().getColumn(2);
|
||||
const Vec3& k1 = m_kart->getXYZ();
|
||||
const Vec3 k2 = k1+forw_vec;
|
||||
return xyz.sideOfLine2D(k1, k2)>0;
|
||||
} // isLeftSideOfKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function is called when the swatter reaches the hit angle (i.e. it
|
||||
* is furthest down). Check all karts if any one is hit, i.e. is at the right
|
||||
* side and at the right angle and distance.
|
||||
* \param isWattingLeft True if the swatter is aiming to the left side
|
||||
* of the kart.
|
||||
*/
|
||||
void Attachment::checkForHitKart(bool isSwattingLeft)
|
||||
{
|
||||
// Square of the minimum distance
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
float min_dist2 = kp->getSwatterDistance2();
|
||||
Kart *hit_kart = NULL;
|
||||
Vec3 forw_vec = m_kart->getTrans().getBasis().getColumn(2);
|
||||
const World *world = World::getWorld();
|
||||
|
||||
for(unsigned int i=0; i<world->getNumKarts(); i++)
|
||||
{
|
||||
Kart *kart = world->getKart(i);
|
||||
if(kart->isEliminated() || kart==m_kart || kart->isSquashed())
|
||||
continue;
|
||||
float f = (kart->getXYZ()-m_kart->getXYZ()).length2();
|
||||
|
||||
// Distance is too great, ignore this kart.
|
||||
if(f>min_dist2) continue;
|
||||
|
||||
// Check if the kart is at the right side.
|
||||
const bool left = isLeftSideOfKart(kart->getXYZ());
|
||||
if(left!=isSwattingLeft)
|
||||
{
|
||||
//printf("%s wrong side: %d %d\n",
|
||||
// kart->getIdent().c_str(), left, isSwattingLeft);
|
||||
continue;
|
||||
}
|
||||
|
||||
Vec3 kart_vec = m_kart->getXYZ()-kart->getXYZ();
|
||||
// cos alpha = a*b/||a||/||b||
|
||||
// Since forw_vec is a unit vector, we only have to divide by
|
||||
// the length of the vector to the kart.
|
||||
float cos_angle = kart_vec.dot(forw_vec)/kart_vec.length();
|
||||
float angle = acosf(cos_angle)*180/M_PI;
|
||||
if(angle<45 || angle>135)
|
||||
{
|
||||
//printf("%s angle %f\n", kart->getIdent().c_str(), angle);
|
||||
continue;
|
||||
}
|
||||
|
||||
kart->setSquash(kp->getSquashDuration(),
|
||||
kp->getSquashSlowdown());
|
||||
// It is assumed that only one kart is within reach of the swatter,
|
||||
// so we can stop testing karts here.
|
||||
return;
|
||||
} // for i < num_karts
|
||||
|
||||
} // angleToKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Checks for any kart that is not already squashed that is close enough.
|
||||
* If a kart is found, it changes the state of the swatter to be
|
||||
* SWATTER_TARGET and starts the animation.
|
||||
*/
|
||||
void Attachment::aimSwatter()
|
||||
{
|
||||
const World *world = World::getWorld();
|
||||
Kart *min_kart = NULL;
|
||||
// Square of the minimum distance
|
||||
float min_dist2 = m_kart->getKartProperties()->getSwatterDistance2();
|
||||
|
||||
for(unsigned int i=0; i<world->getNumKarts(); i++)
|
||||
{
|
||||
Kart *kart = world->getKart(i);
|
||||
if(kart->isEliminated() || kart==m_kart || kart->isSquashed())
|
||||
continue;
|
||||
float f = (kart->getXYZ()-m_kart->getXYZ()).length2();
|
||||
if(f<min_dist2)
|
||||
{
|
||||
min_dist2 = f;
|
||||
min_kart = kart;
|
||||
}
|
||||
}
|
||||
// No kart close enough, nothing to do.
|
||||
if(!min_kart) return;
|
||||
|
||||
m_count --;
|
||||
m_animation_phase = SWATTER_TO_KART;
|
||||
m_animation_target = min_kart;
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
m_animation_timer = kp->getSwatterAnimationTime();
|
||||
const bool left = isLeftSideOfKart(min_kart->getXYZ());
|
||||
m_rot_per_sec = core::vector3df(0, 0,
|
||||
left ?90.0f:-90.0f) / m_animation_timer;
|
||||
|
||||
} // aimSwatter
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Starts a (smaller) and faster swatting movement to be played
|
||||
* when the kart is hit by an item.
|
||||
*/
|
||||
void Attachment::swatItem()
|
||||
{
|
||||
assert(m_type==ATTACH_SWATTER);
|
||||
assert(m_animation_target==NULL);
|
||||
|
||||
m_animation_phase = SWATTER_ITEM_1;
|
||||
m_animation_timer =
|
||||
m_kart->getKartProperties()->getSwatterItemAnimationTime();
|
||||
m_count--;
|
||||
m_rot_per_sec = core::vector3df(0, 0, SWAT_ANGLE) / m_animation_timer;
|
||||
} // swatItem
|
||||
|
@ -27,72 +27,115 @@
|
||||
class Kart;
|
||||
class Item;
|
||||
|
||||
// Some loop in attachment.cpp depend on ATTACH_FIRST and ATTACH_MAX.
|
||||
// So if new elements are added, make sure to add them in between those values.
|
||||
// Also, please note that Attachment::Attachment relies on ATTACH_FIRST being 0.
|
||||
enum attachmentType
|
||||
{
|
||||
ATTACH_FIRST = 0,
|
||||
ATTACH_PARACHUTE = 0,
|
||||
ATTACH_BOMB,
|
||||
ATTACH_ANVIL,
|
||||
ATTACH_TINYTUX,
|
||||
ATTACH_MAX,
|
||||
ATTACH_NOTHING
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup items
|
||||
*/
|
||||
class Attachment: public NoCopy
|
||||
{
|
||||
public:
|
||||
// Some loop in attachment.cpp depend on ATTACH_FIRST and ATTACH_MAX.
|
||||
// So if new elements are added, make sure to add them in between those values.
|
||||
// Also, please note that Attachment::Attachment relies on ATTACH_FIRST being 0.
|
||||
enum AttachmentType
|
||||
{
|
||||
ATTACH_FIRST = 0,
|
||||
ATTACH_PARACHUTE = 0,
|
||||
ATTACH_BOMB,
|
||||
ATTACH_ANVIL,
|
||||
ATTACH_SWATTER,
|
||||
ATTACH_TINYTUX,
|
||||
ATTACH_MAX,
|
||||
ATTACH_NOTHING
|
||||
};
|
||||
|
||||
private:
|
||||
attachmentType m_type; //!< attachment type
|
||||
Kart *m_kart; //!< kart the attachment is attached to
|
||||
float m_time_left; //!< time left till attachment expires
|
||||
float m_initial_speed; //!< for parachutes only
|
||||
/** Attachment type. */
|
||||
AttachmentType m_type;
|
||||
|
||||
/** Kart the attachment is attached to. */
|
||||
Kart *m_kart;
|
||||
|
||||
/** How often an attachment can be used (e.g. swatter). */
|
||||
int m_count;
|
||||
|
||||
/** Time left till attachment expires. */
|
||||
float m_time_left;
|
||||
|
||||
/** For parachutes only. */
|
||||
float m_initial_speed;
|
||||
|
||||
/** Scene node of the attachment, which will be attached to the kart's
|
||||
* scene node. */
|
||||
scene::IAnimatedMeshSceneNode
|
||||
*m_node;
|
||||
Kart *m_previous_owner; //!< used by bombs so that it's not passed
|
||||
//!< back to previous owner
|
||||
|
||||
/** Used by bombs so that it's not passed back to previous owner. */
|
||||
Kart *m_previous_owner;
|
||||
|
||||
/** State of a swatter animation. The swatter is either aiming (looking
|
||||
* for a kart and/or swatting an incoming item), moving towards or back
|
||||
* from a kart, or swatting left and right to hit an item - which has
|
||||
* three phases: going left to an angle a (phae 1), then going to -a
|
||||
* (phase 2), then going back to 0. */
|
||||
enum {SWATTER_AIMING, SWATTER_TO_KART,
|
||||
SWATTER_BACK_FROM_KART,
|
||||
SWATTER_ITEM_1, SWATTER_ITEM_2, SWATTER_ITEM_3,
|
||||
SWATTER_BACK_FROM_ITEM} m_animation_phase;
|
||||
|
||||
/** Timer for swatter animation. */
|
||||
float m_animation_timer;
|
||||
|
||||
/** The kart the swatter is aiming at. */
|
||||
Kart *m_animation_target;
|
||||
|
||||
/** Rotation per second so that the swatter will hit the kart. */
|
||||
core::vector3df m_rot_per_sec;
|
||||
|
||||
RandomGenerator m_random;
|
||||
|
||||
void aimSwatter();
|
||||
bool isLeftSideOfKart(const Vec3 &xyz);
|
||||
void checkForHitKart(bool isSwattingToLeft);
|
||||
|
||||
public:
|
||||
Attachment(Kart* _kart);
|
||||
~Attachment();
|
||||
void set (attachmentType _type, float time, Kart *previous_kart=NULL);
|
||||
void set (attachmentType _type) { set(_type, m_time_left); }
|
||||
void clear ();
|
||||
attachmentType getType () const { return m_type; }
|
||||
float getTimeLeft () const { return m_time_left; }
|
||||
void setTimeLeft (float t){ m_time_left = t; }
|
||||
Kart* getPreviousOwner () const { return m_previous_owner; }
|
||||
|
||||
float weightAdjust () const {
|
||||
return m_type==ATTACH_ANVIL
|
||||
?stk_config->m_anvil_weight:0.0f;
|
||||
}
|
||||
|
||||
float airResistanceAdjust () const {
|
||||
return m_type==ATTACH_PARACHUTE
|
||||
?stk_config->m_parachute_friction:0.0f;
|
||||
}
|
||||
|
||||
float speedAdjust () const {
|
||||
return m_type==ATTACH_ANVIL
|
||||
?stk_config->m_anvil_speed_factor:1.0f;
|
||||
}
|
||||
|
||||
/** 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
|
||||
*/
|
||||
Attachment(Kart* kart);
|
||||
~Attachment();
|
||||
void clear ();
|
||||
void hitBanana(Item *item, int new_attachment=-1);
|
||||
void update (float dt);
|
||||
void updateSwatter(float dt);
|
||||
void moveBombFromTo(Kart *from, Kart *to);
|
||||
};
|
||||
void swatItem();
|
||||
|
||||
void set (AttachmentType type, float time, Kart *previous_kart=NULL);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the type of the attachment, but keeps the old time left value. */
|
||||
void set (AttachmentType type) { set(type, m_time_left); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the type of this attachment. */
|
||||
AttachmentType getType() const { return m_type; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how much time is left before this attachment is removed. */
|
||||
float getTimeLeft() const { return m_time_left; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets how long this attachment will remain attached. */
|
||||
void setTimeLeft(float t){ m_time_left = t; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the previous owner of this attachment, used in bombs that
|
||||
* are being passed between karts. */
|
||||
Kart* getPreviousOwner() const { return m_previous_owner; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns additional weight for the kart. */
|
||||
float weightAdjust() const {
|
||||
return m_type==ATTACH_ANVIL ? stk_config->m_anvil_weight : 0.0f; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the swatter is currently aiming, i.e. can be used to
|
||||
* swat an incoming projectile. */
|
||||
bool isSwatterReady() const {
|
||||
assert(m_type==ATTACH_SWATTER);
|
||||
return m_animation_phase == SWATTER_AIMING;
|
||||
} // isSwatterReady
|
||||
// ------------------------------------------------------------------------
|
||||
}; // Attachment
|
||||
|
||||
#endif
|
||||
|
@ -25,7 +25,9 @@
|
||||
|
||||
AttachmentManager *attachment_manager = 0;
|
||||
|
||||
struct initAttachmentType {attachmentType attachment; const char *file; const char *icon_file;};
|
||||
struct initAttachmentType {Attachment::AttachmentType attachment;
|
||||
const char *file;
|
||||
const char *icon_file;};
|
||||
|
||||
/* Some explanations to the attachments:
|
||||
Parachute: This will increase the air friction, reducing the maximum speed.
|
||||
@ -46,17 +48,18 @@ struct initAttachmentType {attachmentType attachment; const char *file; const c
|
||||
|
||||
initAttachmentType iat[]=
|
||||
{
|
||||
{ATTACH_PARACHUTE, "parachute.b3d", "parachute-attach-icon.png"},
|
||||
{ATTACH_BOMB, "bomb.b3d", "bomb-attach-icon.png" },
|
||||
{ATTACH_ANVIL, "anchor.b3d", "anchor-attach-icon.png" },
|
||||
{ATTACH_TINYTUX, "reset-button.b3d","reset-attach-icon.png" },
|
||||
{ATTACH_MAX, "", "" },
|
||||
{Attachment::ATTACH_PARACHUTE, "parachute.b3d", "parachute-attach-icon.png"},
|
||||
{Attachment::ATTACH_BOMB, "bomb.b3d", "bomb-attach-icon.png" },
|
||||
{Attachment::ATTACH_ANVIL, "anchor.b3d", "anchor-attach-icon.png" },
|
||||
{Attachment::ATTACH_SWATTER, "swatter.b3d", "swatter-icon.png" },
|
||||
{Attachment::ATTACH_TINYTUX, "reset-button.b3d","reset-attach-icon.png" },
|
||||
{Attachment::ATTACH_MAX, "", "" },
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
AttachmentManager::~AttachmentManager()
|
||||
{
|
||||
for(int i=0; iat[i].attachment!=ATTACH_MAX; i++)
|
||||
for(int i=0; iat[i].attachment!=Attachment::ATTACH_MAX; i++)
|
||||
{
|
||||
scene::IMesh *mesh = m_attachments[iat[i].attachment];
|
||||
mesh->drop();
|
||||
@ -73,7 +76,7 @@ AttachmentManager::~AttachmentManager()
|
||||
//-----------------------------------------------------------------------------
|
||||
void AttachmentManager::removeTextures()
|
||||
{
|
||||
for(int i=0; iat[i].attachment!=ATTACH_MAX; i++)
|
||||
for(int i=0; iat[i].attachment!=Attachment::ATTACH_MAX; i++)
|
||||
{
|
||||
// FIXME: free attachment textures
|
||||
} // for
|
||||
@ -82,7 +85,7 @@ void AttachmentManager::removeTextures()
|
||||
//-----------------------------------------------------------------------------
|
||||
void AttachmentManager::loadModels()
|
||||
{
|
||||
for(int i=0; iat[i].attachment!=ATTACH_MAX; i++)
|
||||
for(int i=0; iat[i].attachment!=Attachment::ATTACH_MAX; i++)
|
||||
{
|
||||
std::string full_path = file_manager->getModelFile(iat[i].file);
|
||||
m_attachments[iat[i].attachment]=irr_driver->getAnimatedMesh(full_path);
|
||||
|
@ -33,20 +33,23 @@ namespace irr
|
||||
class AttachmentManager: public NoCopy
|
||||
{
|
||||
private:
|
||||
scene::IAnimatedMesh *m_attachments[ATTACH_MAX];
|
||||
Material *m_all_icons [ATTACH_MAX];
|
||||
scene::IAnimatedMesh *m_attachments[Attachment::ATTACH_MAX];
|
||||
Material *m_all_icons [Attachment::ATTACH_MAX];
|
||||
public:
|
||||
AttachmentManager() {};
|
||||
~AttachmentManager();
|
||||
void removeTextures ();
|
||||
void loadModels ();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the mest for a certain attachment.
|
||||
* \param type Type of the attachment needed. */
|
||||
scene::IAnimatedMesh *getMesh(attachmentType type) const {return m_attachments[type]; }
|
||||
scene::IAnimatedMesh *getMesh(Attachment::AttachmentType type) const
|
||||
{return m_attachments[type]; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the icon to display in the race gui if a kart
|
||||
* has an attachment. */
|
||||
const Material*
|
||||
getIcon (int type) const {return m_all_icons [type];}
|
||||
const Material* getIcon (int type) const {return m_all_icons [type]; }
|
||||
// ------------------------------------------------------------------------
|
||||
};
|
||||
|
||||
extern AttachmentManager *attachment_manager;
|
||||
|
@ -142,6 +142,10 @@ void Powerup::set(PowerupManager::PowerupType type, int n)
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
// No sound effect when arming the glove
|
||||
case PowerupManager::POWERUP_SWATTER:
|
||||
break;
|
||||
|
||||
case PowerupManager::POWERUP_ZIPPER:
|
||||
break ;
|
||||
|
||||
@ -193,6 +197,7 @@ void Powerup::use()
|
||||
{
|
||||
// Play custom kart sound when collectible is used
|
||||
if (m_type != PowerupManager::POWERUP_NOTHING &&
|
||||
m_type != PowerupManager::POWERUP_SWATTER &&
|
||||
m_type != PowerupManager::POWERUP_ZIPPER)
|
||||
m_owner->playCustomSFX(SFXManager::CUSTOM_SHOOT);
|
||||
|
||||
@ -247,7 +252,11 @@ void Powerup::use()
|
||||
m_sound_use->play();
|
||||
projectile_manager->newProjectile(m_owner, m_type);
|
||||
break ;
|
||||
|
||||
|
||||
case PowerupManager::POWERUP_SWATTER:
|
||||
m_owner->getAttachment()->set(Attachment::ATTACH_SWATTER,
|
||||
m_owner->getKartProperties()->getSwatterDuration());
|
||||
break;
|
||||
case PowerupManager::POWERUP_BUBBLEGUM:
|
||||
{
|
||||
Vec3 hit_point;
|
||||
@ -302,7 +311,8 @@ void Powerup::use()
|
||||
if(kart == m_owner) continue;
|
||||
if(kart->getPosition() == 1)
|
||||
{
|
||||
kart->attach(ATTACH_ANVIL, stk_config->m_anvil_time);
|
||||
kart->attach(Attachment::ATTACH_ANVIL,
|
||||
stk_config->m_anvil_time);
|
||||
kart->updatedWeight();
|
||||
kart->adjustSpeed(stk_config->m_anvil_speed_factor*0.5f);
|
||||
|
||||
@ -338,7 +348,8 @@ void Powerup::use()
|
||||
if(kart->isEliminated() || kart== m_owner) continue;
|
||||
if(m_owner->getPosition() > kart->getPosition())
|
||||
{
|
||||
kart->attach(ATTACH_PARACHUTE, stk_config->m_parachute_time_other);
|
||||
kart->attach(Attachment::ATTACH_PARACHUTE,
|
||||
stk_config->m_parachute_time_other);
|
||||
|
||||
if(kart->getController()->isPlayerController())
|
||||
player_kart = kart;
|
||||
|
@ -93,7 +93,7 @@ PowerupManager::PowerupType
|
||||
static std::string powerup_names[] = {
|
||||
"", /* Nothing */
|
||||
"bubblegum", "cake", "bowling", "zipper", "plunger", "switch",
|
||||
"parachute", "anchor"
|
||||
"swatter", "parachute", "anchor"
|
||||
};
|
||||
|
||||
for(unsigned int i=POWERUP_FIRST; i<=POWERUP_LAST; i++)
|
||||
|
@ -79,7 +79,7 @@ public:
|
||||
POWERUP_BUBBLEGUM = POWERUP_FIRST,
|
||||
POWERUP_CAKE,
|
||||
POWERUP_BOWLING, POWERUP_ZIPPER, POWERUP_PLUNGER,
|
||||
POWERUP_SWITCH,
|
||||
POWERUP_SWITCH, POWERUP_SWATTER,
|
||||
POWERUP_PARACHUTE,
|
||||
POWERUP_ANVIL, //powerup.cpp assumes these two come last
|
||||
POWERUP_LAST=POWERUP_ANVIL,
|
||||
|
@ -205,7 +205,8 @@ void DefaultAIController::update(float dt)
|
||||
// Special behaviour if we have a bomb attach: try to hit the kart ahead
|
||||
// of us.
|
||||
bool commands_set = false;
|
||||
if(m_handle_bomb && m_kart->getAttachment()->getType()==ATTACH_BOMB &&
|
||||
if(m_handle_bomb &&
|
||||
m_kart->getAttachment()->getType()==Attachment::ATTACH_BOMB &&
|
||||
m_kart_ahead )
|
||||
{
|
||||
// Use nitro if the kart is far ahead, or faster than this kart
|
||||
@ -559,6 +560,23 @@ void DefaultAIController::handleItems(const float dt)
|
||||
}
|
||||
break; // POWERUP_ANVIL
|
||||
|
||||
case PowerupManager::POWERUP_SWATTER:
|
||||
{
|
||||
// Squared distance for which the swatter works
|
||||
float d2 = m_kart->getKartProperties()->getSwatterDistance2();
|
||||
// Fire if the closest kart ahead or to the back is not already
|
||||
// squashed and close enough.
|
||||
// FIXME: this can be improved on, since more than one kart might
|
||||
// be hit, and a kart ahead might not be at an angle at
|
||||
// which the glove can be used.
|
||||
if( ( m_kart_ahead && !m_kart_ahead->isSquashed() &&
|
||||
(m_kart_ahead->getXYZ()-m_kart->getXYZ()).length2()<d2 &&
|
||||
m_kart_ahead->getSpeed() < m_kart->getSpeed() ) ||
|
||||
( m_kart_behind && !m_kart_behind->isSquashed() &&
|
||||
(m_kart_behind->getXYZ()-m_kart->getXYZ()).length2()<d2) )
|
||||
m_controls->m_fire = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Invalid or unhandled powerup '%d' in default AI.\n",
|
||||
m_kart->getPowerup()->getType());
|
||||
@ -728,8 +746,8 @@ void DefaultAIController::handleNitroAndZipper()
|
||||
// If a parachute or anvil is attached, the nitro doesn't give much
|
||||
// benefit. Better wait till later.
|
||||
const bool has_slowdown_attachment =
|
||||
m_kart->getAttachment()->getType()==ATTACH_PARACHUTE ||
|
||||
m_kart->getAttachment()->getType()==ATTACH_ANVIL;
|
||||
m_kart->getAttachment()->getType()==Attachment::ATTACH_PARACHUTE ||
|
||||
m_kart->getAttachment()->getType()==Attachment::ATTACH_ANVIL;
|
||||
if(has_slowdown_attachment) return;
|
||||
|
||||
// If the kart is very slow (e.g. after rescue), use nitro
|
||||
|
@ -148,7 +148,8 @@ void NewAIController::update(float dt)
|
||||
// Special behaviour if we have a bomb attach: try to hit the kart ahead
|
||||
// of us.
|
||||
bool commands_set = false;
|
||||
if(m_handle_bomb && m_kart->getAttachment()->getType()==ATTACH_BOMB &&
|
||||
if(m_handle_bomb &&
|
||||
m_kart->getAttachment()->getType()==Attachment::ATTACH_BOMB &&
|
||||
m_kart_ahead )
|
||||
{
|
||||
// Use nitro if the kart is far ahead, or faster than this kart
|
||||
@ -442,6 +443,7 @@ void NewAIController::handleItems( const float DELTA, const int STEPS )
|
||||
m_controls->m_fire = m_time_since_last_shot > 3.0f &&
|
||||
m_kart->getPosition()>1;
|
||||
}
|
||||
case PowerupManager::POWERUP_SWATTER: // fallthrough
|
||||
default:
|
||||
m_controls->m_fire = true;
|
||||
}
|
||||
@ -600,8 +602,8 @@ void NewAIController::handleNitroAndZipper()
|
||||
// If a parachute or anvil is attached, the nitro doesn't give much
|
||||
// benefit. Better wait till later.
|
||||
const bool has_slowdown_attachment =
|
||||
m_kart->getAttachment()->getType()==ATTACH_PARACHUTE ||
|
||||
m_kart->getAttachment()->getType()==ATTACH_ANVIL;
|
||||
m_kart->getAttachment()->getType()==Attachment::ATTACH_PARACHUTE ||
|
||||
m_kart->getAttachment()->getType()==Attachment::ATTACH_ANVIL;
|
||||
if(has_slowdown_attachment) return;
|
||||
|
||||
// If the kart is very slow (e.g. after rescue), use nitro
|
||||
|
@ -336,7 +336,7 @@ void PlayerController::update(float dt)
|
||||
m_controls->m_rescue=false;
|
||||
}
|
||||
if (m_kart->playingEmergencyAnimation() &&
|
||||
m_kart->getAttachment()->getType() != ATTACH_TINYTUX)
|
||||
m_kart->getAttachment()->getType() != Attachment::ATTACH_TINYTUX)
|
||||
{
|
||||
m_bzzt_sound->play();
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ void EmergencyAnimation::forceRescue(bool is_auto_rescue)
|
||||
m_up_velocity = m_kart->getKartProperties()->getRescueHeight() / m_timer;
|
||||
m_xyz = m_kart->getXYZ();
|
||||
|
||||
m_kart->attach(ATTACH_TINYTUX, m_timer);
|
||||
m_kart->attach(Attachment::ATTACH_TINYTUX, m_timer);
|
||||
|
||||
m_curr_rotation.setPitch(m_kart->getPitch());
|
||||
m_curr_rotation.setRoll(m_kart->getRoll() );
|
||||
@ -137,6 +137,13 @@ void EmergencyAnimation::handleExplosion(const Vec3 &pos, bool direct_hit)
|
||||
if(playingEmergencyAnimation()) return;
|
||||
if(m_kart->isInvulnerable())
|
||||
return;
|
||||
Attachment *a=m_kart->getAttachment();
|
||||
if(a->getType()==Attachment::ATTACH_SWATTER &&
|
||||
a->isSwatterReady())
|
||||
{
|
||||
a->swatItem();
|
||||
return;
|
||||
}
|
||||
|
||||
m_xyz = m_kart->getXYZ();
|
||||
// Ignore explosion that are too far away.
|
||||
|
@ -97,6 +97,7 @@ Kart::Kart (const std::string& ident, Track* track, int position, bool is_first_
|
||||
m_wheel_toggle = 1;
|
||||
m_finish_time = 0.0f;
|
||||
m_invulnerable_time = 0.0f;
|
||||
m_squash_time = 0.0f;
|
||||
m_shadow_enabled = false;
|
||||
m_shadow = NULL;
|
||||
m_terrain_particles = NULL;
|
||||
@ -481,11 +482,12 @@ void Kart::reset()
|
||||
m_camera->reset();
|
||||
m_camera->setInitialTransform();
|
||||
}
|
||||
|
||||
// Stop any animations currently being played.
|
||||
m_kart_model->setAnimation(KartModel::AF_DEFAULT);
|
||||
|
||||
// Reset squashing and animations
|
||||
m_kart_model->resetWheels();
|
||||
|
||||
// If the controller was replaced (e.g. replaced by end controller),
|
||||
// restore the original controller.
|
||||
// restore the original controller.
|
||||
if(m_saved_controller)
|
||||
{
|
||||
m_controller = m_saved_controller;
|
||||
@ -501,6 +503,8 @@ void Kart::reset()
|
||||
m_finished_race = false;
|
||||
m_finish_time = 0.0f;
|
||||
m_invulnerable_time = 0.0f;
|
||||
m_squash_time = 0.0f;
|
||||
m_kart_model->scaleKart(Vec3(1.0f, 1.0f, 1.0f));
|
||||
m_collected_energy = 0;
|
||||
m_has_started = false;
|
||||
m_wheel_rotation = 0;
|
||||
@ -742,6 +746,18 @@ void Kart::update(float dt)
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_squash_time>0)
|
||||
{
|
||||
m_squash_time-=dt;
|
||||
// If squasing time ends, reset the model
|
||||
if(m_squash_time<=0)
|
||||
{
|
||||
m_kart_model->scaleKart(Vec3(1.0f, 1.0f, 1.0f));
|
||||
MaxSpeed::setSlowdown(MaxSpeed::MS_DECREASE_SQUASH,
|
||||
/*slowdown*/1.0f, /*fade in*/0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the position and other data taken from the physics
|
||||
Moveable::update(dt);
|
||||
|
||||
@ -937,6 +953,19 @@ void Kart::update(float dt)
|
||||
}
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Squashes this kart: it will scale the kart in up direction, and causes
|
||||
* a slowdown while this kart is squashed.
|
||||
* \param time How long the kart will be squashed.
|
||||
* \param slowdown Reduction of max speed.
|
||||
*/
|
||||
void Kart::setSquash(float time, float slowdown)
|
||||
{
|
||||
m_kart_model->scaleKart(Vec3(1.0f, 0.5f, 1.0f));
|
||||
MaxSpeed::setSlowdown(MaxSpeed::MS_DECREASE_SQUASH, slowdown, 0.1f);
|
||||
m_squash_time = time;
|
||||
} // setSquash
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Plays any terrain specific sound effect.
|
||||
*/
|
||||
@ -1399,7 +1428,8 @@ void Kart::updatePhysics(float dt)
|
||||
float engine_power = getActualWheelForce() + handleNitro(dt)
|
||||
+ m_slipstream->getSlipstreamPower();
|
||||
|
||||
if(m_attachment->getType()==ATTACH_PARACHUTE) engine_power*=0.2f;
|
||||
if(m_attachment->getType()==Attachment::ATTACH_PARACHUTE)
|
||||
engine_power*=0.2f;
|
||||
|
||||
if (m_flying)
|
||||
{
|
||||
|
@ -120,6 +120,10 @@ private:
|
||||
/** Time a kart is invulnerable. */
|
||||
float m_invulnerable_time;
|
||||
|
||||
/** How long a kart is being squashed. If this is >0
|
||||
* the kart is squashed. */
|
||||
float m_squash_time;
|
||||
|
||||
// Bullet physics parameters
|
||||
// -------------------------
|
||||
btRaycastVehicle::btVehicleTuning
|
||||
@ -225,10 +229,12 @@ public:
|
||||
void adjustSpeed (float f);
|
||||
void capSpeed (float max_speed);
|
||||
void updatedWeight ();
|
||||
virtual void collectedItem (Item *item, int random_attachment);
|
||||
virtual void reset ();
|
||||
virtual void handleZipper (const Material *m=NULL, bool play_sound=false);
|
||||
virtual void crashed (Kart *k, const Material *m=NULL);
|
||||
void collectedItem (Item *item, int random_attachment);
|
||||
void reset ();
|
||||
void handleZipper (const Material *m=NULL, bool play_sound=false);
|
||||
void setSquash (float time, float slowdown);
|
||||
|
||||
void crashed (Kart *k, const Material *m=NULL);
|
||||
|
||||
virtual void update (float dt);
|
||||
virtual void finishedRace (float time);
|
||||
@ -247,8 +253,8 @@ public:
|
||||
void setKartProperties(const KartProperties *kp) { m_kart_properties=kp; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the attachment and time it stays attached. */
|
||||
void attach(attachmentType attachment_, float time)
|
||||
{ m_attachment->set(attachment_, time); }
|
||||
void attach(Attachment::AttachmentType attachment, float time)
|
||||
{ m_attachment->set(attachment, time); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets a new powerup. */
|
||||
void setPowerup (PowerupManager::PowerupType t, int n)
|
||||
@ -420,7 +426,11 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the energy the kart has collected. */
|
||||
void setEnergy(float val) { m_collected_energy = val; }
|
||||
};
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the kart is currently being squashed. */
|
||||
bool isSquashed() const { return m_squash_time >0; }
|
||||
// ------------------------------------------------------------------------
|
||||
}; // Kart
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -376,6 +376,18 @@ void KartModel::setDefaultPhysicsPosition(const Vec3 ¢er_shift,
|
||||
|
||||
} // setDefaultPhysicsPosition
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Resets the kart model. It removes any scaling (squashing) and stops
|
||||
* animation from being played.
|
||||
*/
|
||||
void KartModel::reset()
|
||||
{
|
||||
m_animated_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
|
||||
|
||||
// Stop any animations currently being played.
|
||||
setAnimation(KartModel::AF_DEFAULT);
|
||||
|
||||
} // reset
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Enables- or disables the end animation.
|
||||
* \param type The type of animation to play.
|
||||
@ -529,3 +541,10 @@ void KartModel::resetWheels()
|
||||
const float suspension[4]={0,0,0,0};
|
||||
update(0, 0.0f, suspension);
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Scales the kart model by a certain amount. */
|
||||
void KartModel::scaleKart(const Vec3 &s)
|
||||
{
|
||||
m_animated_node->setScale(s.toIrrVector());
|
||||
} // squashKart
|
@ -141,6 +141,7 @@ public:
|
||||
KartModel(bool is_master);
|
||||
~KartModel();
|
||||
KartModel* makeCopy();
|
||||
void reset();
|
||||
void loadInfo(const XMLNode &node);
|
||||
bool loadModels(const KartProperties &kart_properties);
|
||||
scene::ISceneNode*
|
||||
@ -180,6 +181,7 @@ public:
|
||||
void update(float rotation, float steer, const float suspension[4]);
|
||||
void resetWheels();
|
||||
void setDefaultPhysicsPosition(const Vec3 ¢er_shift, float wheel_radius);
|
||||
void scaleKart(const Vec3 &s);
|
||||
|
||||
/** Enables- or disables the end animation. */
|
||||
void setAnimation(AnimationFrameType type);
|
||||
|
@ -88,9 +88,14 @@ KartProperties::KartProperties(const std::string &filename)
|
||||
m_camera_distance = m_camera_forward_up_angle =
|
||||
m_camera_backward_up_angle = m_explosion_invulnerability_time =
|
||||
m_rescue_time = m_rescue_height = m_explosion_time =
|
||||
m_explosion_radius = m_ai_steering_variation = UNDEFINED;
|
||||
m_explosion_radius = m_ai_steering_variation =
|
||||
m_swatter_distance2 = m_swatter_duration = m_swatter_animation_time =
|
||||
m_swatter_item_animation_time = m_squash_slowdown =
|
||||
m_squash_duration = UNDEFINED;
|
||||
|
||||
m_gravity_center_shift = Vec3(UNDEFINED);
|
||||
m_has_skidmarks = true;
|
||||
m_swatter_count = -1;
|
||||
m_version = 0;
|
||||
m_color = video::SColor(255, 0, 0, 0);
|
||||
m_shape = 32; // close enough to a circle.
|
||||
@ -435,6 +440,23 @@ void KartProperties::getAllData(const XMLNode * root)
|
||||
zipper_node->get("max-speed-increase", &m_zipper_max_speed_increase);
|
||||
}
|
||||
|
||||
if(const XMLNode *swatter_node= root->getNode("swatter"))
|
||||
{
|
||||
swatter_node->get("duration", &m_swatter_duration );
|
||||
swatter_node->get("count", &m_swatter_count );
|
||||
swatter_node->get("animation-time", &m_swatter_animation_time);
|
||||
swatter_node->get("item-animation-time",
|
||||
&m_swatter_item_animation_time);
|
||||
swatter_node->get("squash-duration", &m_squash_duration );
|
||||
swatter_node->get("squash-slowdown", &m_squash_slowdown );
|
||||
if(swatter_node->get("distance", &m_swatter_distance2) )
|
||||
{
|
||||
// Avoid squaring if distance is not defined, so that
|
||||
// distance2 remains UNDEFINED (which is a negative value)
|
||||
m_swatter_distance2 *= m_swatter_distance2;
|
||||
}
|
||||
}
|
||||
|
||||
if(const XMLNode *camera_node= root->getNode("camera"))
|
||||
{
|
||||
camera_node->get("distance", &m_camera_distance);
|
||||
@ -594,6 +616,14 @@ void KartProperties::checkAllSet(const std::string &filename)
|
||||
CHECK_NEG(m_nitro_max_speed_increase, "nitro max-speed-increase" );
|
||||
CHECK_NEG(m_nitro_duration, "nitro duration" );
|
||||
CHECK_NEG(m_nitro_fade_out_time, "nitro fade-out-time" );
|
||||
CHECK_NEG(m_swatter_distance2, "swatter distance" );
|
||||
CHECK_NEG(m_swatter_animation_time, "swatter animation-time" );
|
||||
CHECK_NEG(m_swatter_item_animation_time,"swatter item-animation-time" );
|
||||
CHECK_NEG(m_swatter_duration, "swatter duration" );
|
||||
CHECK_NEG(m_swatter_count, "swatter count" );
|
||||
CHECK_NEG(m_squash_duration, "swatter squash-duration" );
|
||||
CHECK_NEG(m_squash_slowdown, "swatter squash-slowdown" );
|
||||
|
||||
CHECK_NEG(m_rescue_height, "rescue height" );
|
||||
CHECK_NEG(m_rescue_time, "rescue time" );
|
||||
CHECK_NEG(m_rescue_vert_offset, "rescue vert-offset" );
|
||||
|
@ -193,6 +193,21 @@ private:
|
||||
/** Duration during which the increased maximum speed
|
||||
* due to nitro fades out. */
|
||||
float m_nitro_fade_out_time;
|
||||
/** Square of the maximum distance a swatter can operate. */
|
||||
float m_swatter_distance2;
|
||||
/** How often the swatter can be fired. */
|
||||
int m_swatter_count;
|
||||
/** How long the swatter lasts. */
|
||||
float m_swatter_duration;
|
||||
/** How long a kart will remain squashed. */
|
||||
float m_squash_duration;
|
||||
/** The slowdown to apply while a kart is squashed. The new maxspeed
|
||||
* is max_speed*m_squash_slowdown. */
|
||||
float m_squash_slowdown;
|
||||
/** Animation time for the swatter. */
|
||||
float m_swatter_animation_time;
|
||||
/** How long the item swatting animation will last. */
|
||||
float m_swatter_item_animation_time;
|
||||
|
||||
/** Engine sound effect. */
|
||||
std::string m_engine_sfx_type;
|
||||
@ -295,7 +310,9 @@ public:
|
||||
~KartProperties ();
|
||||
void getAllData (const XMLNode * root);
|
||||
void checkAllSet(const std::string &filename);
|
||||
float getStartupBoost() const;
|
||||
|
||||
/** Returns the maximum steering angle (depending on speed). */
|
||||
float getMaxSteerAngle (float speed) const;
|
||||
|
||||
/** Returns the material for the kart icons. */
|
||||
@ -492,24 +509,27 @@ public:
|
||||
/** Return the fade out time once a rubber band is removed. */
|
||||
float getRubberBandFadeOutTime () const {return m_rubber_band_fade_out_time;}
|
||||
|
||||
|
||||
/** Returns duration of a plunger in your face. */
|
||||
float getPlungerInFaceTime () const
|
||||
{return m_plunger_in_face_duration[race_manager->getDifficulty()];}
|
||||
|
||||
/** Returns the time a zipper is active. */
|
||||
float getZipperTime () const {return m_zipper_time; }
|
||||
|
||||
/** Returns the time a zipper is active. */
|
||||
float getZipperFadeOutTime () const {return m_zipper_fade_out_time; }
|
||||
|
||||
/** Returns the additional force added applied to the kart. */
|
||||
float getZipperForce () const { return m_zipper_force; }
|
||||
|
||||
/** Returns the initial zipper speed gain. */
|
||||
float getZipperSpeedGain () const { return m_zipper_speed_gain; }
|
||||
|
||||
/** Returns the increase of the maximum speed of the kart
|
||||
* if a zipper is active. */
|
||||
float getZipperMaxSpeedIncrease () const
|
||||
{ return m_zipper_max_speed_increase;}
|
||||
|
||||
|
||||
/** Returns additional rotation of 3d model when skidding. */
|
||||
float getSkidVisual () const {return m_skid_visual; }
|
||||
|
||||
@ -585,8 +605,30 @@ public:
|
||||
|
||||
/** Returns the full path where the files for this kart are stored. */
|
||||
const std::string& getKartDir () const {return m_root; }
|
||||
float getStartupBoost() const;
|
||||
};
|
||||
|
||||
/** Returns the square of the maximum distance at which a swatter
|
||||
* can hit karts. */
|
||||
float getSwatterDistance2() const { return m_swatter_distance2; }
|
||||
|
||||
/** Returns how often a swatter can be used. */
|
||||
int getSwatterCount() const { return m_swatter_count; }
|
||||
|
||||
/** Returns how long a swatter will stay attached/ready to be used. */
|
||||
float getSwatterDuration() const { return m_swatter_duration; }
|
||||
|
||||
/** Returns how long a kart remains squashed. */
|
||||
float getSquashDuration() const {return m_squash_duration; }
|
||||
|
||||
/** Returns the slowdown of a kart that is squashed. */
|
||||
float getSquashSlowdown() const {return m_squash_slowdown; }
|
||||
|
||||
/** Returns how long it takes for the swatter to hit a target. */
|
||||
float getSwatterAnimationTime() const { return m_swatter_animation_time; }
|
||||
|
||||
/** Returns how long it takes for the swatter to swat at an item. */
|
||||
float getSwatterItemAnimationTime() const
|
||||
{return m_swatter_item_animation_time; }
|
||||
}; // KartProperties
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
enum {MS_DECREASE_MIN,
|
||||
MS_DECREASE_TERRAIN = MS_DECREASE_MIN,
|
||||
MS_DECREASE_AI,
|
||||
MS_DECREASE_SQUASH,
|
||||
MS_DECREASE_MAX};
|
||||
|
||||
private:
|
||||
|
@ -974,6 +974,12 @@ int main(int argc, char *argv[] )
|
||||
UserConfigParams::m_internet_status = NetworkHttp::IPERM_ALLOWED;
|
||||
GUIEngine::ModalDialog::dismiss();
|
||||
network_http = new NetworkHttp();
|
||||
// Note that the network thread must be started after
|
||||
// the assignment to network_http (since the thread
|
||||
// might use network_http, otherwise a race condition
|
||||
// can be introduced resulting in a crash).
|
||||
network_http->startNetworkThread();
|
||||
|
||||
} // onConfirm
|
||||
// --------------------------------------------------------
|
||||
virtual void onCancel()
|
||||
@ -982,6 +988,7 @@ int main(int argc, char *argv[] )
|
||||
UserConfigParams::m_internet_status = NetworkHttp::IPERM_NOT_ALLOWED;
|
||||
GUIEngine::ModalDialog::dismiss();
|
||||
network_http = new NetworkHttp();
|
||||
network_http->startNetworkThread();
|
||||
} // onCancel
|
||||
}; // ConfirmServer
|
||||
|
||||
|
@ -180,10 +180,10 @@ void Physics::KartKartCollision(Kart *kartA, Kart *kartB)
|
||||
Attachment *attachmentA=kartA->getAttachment();
|
||||
Attachment *attachmentB=kartB->getAttachment();
|
||||
|
||||
if(attachmentA->getType()==ATTACH_BOMB)
|
||||
if(attachmentA->getType()==Attachment::ATTACH_BOMB)
|
||||
{
|
||||
// If both karts have a bomb, explode them immediately:
|
||||
if(attachmentB->getType()==ATTACH_BOMB)
|
||||
if(attachmentB->getType()==Attachment::ATTACH_BOMB)
|
||||
{
|
||||
attachmentA->setTimeLeft(0.0f);
|
||||
attachmentB->setTimeLeft(0.0f);
|
||||
@ -198,7 +198,7 @@ void Physics::KartKartCollision(Kart *kartA, Kart *kartB)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(attachmentB->getType()==ATTACH_BOMB &&
|
||||
else if(attachmentB->getType()==Attachment::ATTACH_BOMB &&
|
||||
attachmentB->getPreviousOwner()!=kartA)
|
||||
{
|
||||
attachmentB->moveBombFromTo(kartB, kartA);
|
||||
|
@ -556,7 +556,7 @@ void RaceGUI::drawGlobalPlayerIcons(const KartIconDisplayInfo* info)
|
||||
}
|
||||
}
|
||||
//attachment
|
||||
if (kart->getAttachment()->getType() != ATTACH_NOTHING)
|
||||
if (kart->getAttachment()->getType() != Attachment::ATTACH_NOTHING)
|
||||
{
|
||||
video::ITexture *icon_attachment =
|
||||
attachment_manager->getIcon(kart->getAttachment()->getType())
|
||||
|
@ -29,8 +29,8 @@
|
||||
Quad::Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
|
||||
bool invisible, bool ai_ignore)
|
||||
{
|
||||
if(sideOfLine2D(p0, p2, p1)>0 ||
|
||||
sideOfLine2D(p0, p2, p3)<0)
|
||||
if(p1.sideOfLine2D(p0, p2)>0 ||
|
||||
p3.sideOfLine2D(p0, p2)<0)
|
||||
{
|
||||
printf("Warning: quad has wrong orientation: p0=%f %f %f p1=%f %f %f\n",
|
||||
p0.getX(), p0.getY(), p0.getZ(),p1.getX(), p1.getY(), p1.getZ());
|
||||
@ -85,16 +85,6 @@ void Quad::getVertices(video::S3DVertex *v, const video::SColor &color) const
|
||||
v[3].Color = color;
|
||||
} // setVertices
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Returns wether a point is to the left or to the right of a line.
|
||||
* While all arguments are 3d, only the x and y coordinates are actually used.
|
||||
*/
|
||||
float Quad::sideOfLine2D(const Vec3& l1, const Vec3& l2, const Vec3& p) const
|
||||
{
|
||||
return (l2.getX()-l1.getX())*(p.getZ()-l1.getZ()) -
|
||||
(l2.getZ()-l1.getZ())*(p.getX()-l1.getX());
|
||||
} // sideOfLine
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool Quad::pointInQuad(const Vec3& p) const
|
||||
{
|
||||
@ -113,12 +103,12 @@ bool Quad::pointInQuad(const Vec3& p) const
|
||||
// If a point is exactly on the line of two quads (e.g. between points
|
||||
// 0,1 on one quad, and 3,2 of the previous quad), assign this point
|
||||
// to be on the 'later' quad, i.e. on the line between points 0 and 1.
|
||||
if(sideOfLine2D(m_p[0], m_p[2], p)<0) {
|
||||
return sideOfLine2D(m_p[0], m_p[1], p) >= 0.0 &&
|
||||
sideOfLine2D(m_p[1], m_p[2], p) >= 0.0;
|
||||
if(p.sideOfLine2D(m_p[0], m_p[2])<0) {
|
||||
return p.sideOfLine2D(m_p[0], m_p[1]) >= 0.0 &&
|
||||
p.sideOfLine2D(m_p[1], m_p[2]) >= 0.0;
|
||||
} else {
|
||||
return sideOfLine2D(m_p[2], m_p[3], p) > 0.0 &&
|
||||
sideOfLine2D(m_p[3], m_p[0], p) >= 0.0;
|
||||
return p.sideOfLine2D(m_p[2], m_p[3]) > 0.0 &&
|
||||
p.sideOfLine2D(m_p[3], m_p[0]) >= 0.0;
|
||||
}
|
||||
} // pointInQuad
|
||||
|
||||
|
@ -54,7 +54,6 @@ private:
|
||||
/** Set if this quad should not be used by the AI. */
|
||||
bool m_ai_ignore;
|
||||
|
||||
float sideOfLine2D(const Vec3& l1, const Vec3& l2, const Vec3& p) const;
|
||||
public:
|
||||
Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
|
||||
bool invis=false, bool ai_ignore=false);
|
||||
|
@ -123,6 +123,19 @@ public:
|
||||
void min(const Vec3& a) {if(a.getX()<m_floats[0]) m_floats[0]=a.getX();
|
||||
if(a.getY()<m_floats[1]) m_floats[1]=a.getY();
|
||||
if(a.getZ()<m_floats[2]) m_floats[2]=a.getZ();}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Determines which side of a line this point is. This is using
|
||||
* a 2d projection (into the X-Z plane).
|
||||
* \param start The start point of the line.
|
||||
* \param end The end point of the line.
|
||||
* \return >0 Point is to the left side; <0 if it's on the right.
|
||||
*/
|
||||
float sideOfLine2D(const Vec3& start, const Vec3& end) const
|
||||
{
|
||||
return (end.getX()-start.getX())*(m_floats[2]-start.getZ()) -
|
||||
(end.getZ()-start.getZ())*(m_floats[0]-start.getX());
|
||||
|
||||
} // sideOfLine2D
|
||||
}; // Vec3
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user