[Change] Split engine sounds and GUI sounds for player.

[Fix] Some issues in sound.c
[Add] More documentation.
This commit is contained in:
Allanis 2013-09-04 15:19:04 +01:00
parent ffdb20f50b
commit 9178376c28
5 changed files with 266 additions and 59 deletions

View File

@ -1,3 +1,9 @@
/**
* @file input.c
*
* @brief Handle all the keybindings and input.
*/
#include "lephisto.h" #include "lephisto.h"
#include "log.h" #include "log.h"
#include "player.h" #include "player.h"
@ -8,18 +14,18 @@
#include "map.h" #include "map.h"
#include "input.h" #include "input.h"
#define KEY_PRESS ( 1.) #define KEY_PRESS ( 1.) /**< Key is pressed. */
#define KEY_RELEASE (-1.) #define KEY_RELEASE (-1.) /**< Key is released. */
/* Keybind structure. */ /* Keybind structure. */
typedef struct Keybind_ { typedef struct Keybind_ {
char* name; /* Keybinding name, taken from keybindNames[] */ char* name; /**< Keybinding name, taken from keybindNames[] */
KeybindType type; /* type, defined in player.h. */ KeybindType type; /**< type, defined in player.h. */
unsigned int key; /* Key/axis/button event number. */ unsigned int key; /**< Key/axis/button event number. */
double reverse; /* 1. if normal, -1 if reversed, only useful for joystick axis. */ double reverse; /**< 1. if normal, -1 if reversed, only useful for joystick axis. */
} Keybind; } Keybind;
static Keybind** input_keybinds; /* Contains the players keybindings. */ static Keybind** input_keybinds; /**< Contains the players keybindings. */
/* Name of each keybinding. */ /* Name of each keybinding. */
@ -33,8 +39,8 @@ const char* keybindNames[] = {
"end" }; /* Must terminate at the end. */ "end" }; /* Must terminate at the end. */
/* Accel hacks. */ /* Accel hacks. */
static unsigned int input_accelLast = 0; /* Used to see if double tap. */ static unsigned int input_accelLast = 0; /**< Used to see if double tap. */
unsigned int input_afterburnSensibility = 200; /* ms between taps to afterburn. */ unsigned int input_afterburnSensibility = 200; /**< ms between taps to afterburn. */
/* From player.c */ /* From player.c */
extern double player_turn; extern double player_turn;
@ -43,7 +49,11 @@ extern unsigned int player_target;
extern int show_fps; extern int show_fps;
/* Set the default input keys. */ /**
* @fn void input_setDefault(void)
*
* @brief Set the default input keys.
*/
void input_setDefault(void) { void input_setDefault(void) {
/* Movement. */ /* Movement. */
input_setKeybind("accel", KEYBIND_KEYBOARD, SDLK_w, 0); input_setKeybind("accel", KEYBIND_KEYBOARD, SDLK_w, 0);
@ -76,7 +86,11 @@ void input_setDefault(void) {
input_setKeybind("info", KEYBIND_KEYBOARD, SDLK_i, 0); input_setKeybind("info", KEYBIND_KEYBOARD, SDLK_i, 0);
} }
/* Initialization/exit functions (does not assign keys). */ /**
* @fn void input_init(void)
*
* @brief Initialize the input subsystem (does not set keys).
*/
void input_init(void) { void input_init(void) {
Keybind* tmp; Keybind* tmp;
int i; int i;
@ -94,6 +108,11 @@ void input_init(void) {
} }
} }
/**
* @fn void input_exit(void)
*
* @brief Exit the input subsystem.
*/
void input_exit(void) { void input_exit(void) {
int i; int i;
for(i = 0; strcmp(keybindNames[i], "end"); i++) for(i = 0; strcmp(keybindNames[i], "end"); i++)
@ -101,7 +120,15 @@ void input_exit(void) {
free(input_keybinds); free(input_keybinds);
} }
/* Binds key of type [type] to action keybind. */ /**
* @fn void input_setKeybind(char* keybind, KeybindType type, int key, int reverse)
*
* @brief Bind a key of type to action keybind.
* @param keybind The name of the keybind defined above.
* @param type The type of the keybind.
* @param key The key to bind to.
* @param reverse Whether to reverse it or not.
*/
void input_setKeybind(char* keybind, KeybindType type, int key, int reverse) { void input_setKeybind(char* keybind, KeybindType type, int key, int reverse) {
int i; int i;
for(i = 0; strcmp(keybindNames[i], "end"); i++) for(i = 0; strcmp(keybindNames[i], "end"); i++)
@ -114,7 +141,10 @@ void input_setKeybind(char* keybind, KeybindType type, int key, int reverse) {
WARN("Unable to set keybind '%s', That command does not exist.", keybind); WARN("Unable to set keybind '%s', That command does not exist.", keybind);
} }
/* Get the value of a keybind. */ /* @fn int input_getKeybind(char* keybind, KeybindType* type, int* reverse)
*
* @brief Get the value of a keybind.
*/
int input_getKeybind(char* keybind, KeybindType* type, int* reverse) { int input_getKeybind(char* keybind, KeybindType* type, int* reverse) {
int i; int i;
for(i = 0; strcmp(keybindNames[i], "end"); i++) for(i = 0; strcmp(keybindNames[i], "end"); i++)
@ -128,14 +158,16 @@ int input_getKeybind(char* keybind, KeybindType* type, int* reverse) {
return -1; return -1;
} }
/* == Run input method. ================================================ */ /**
/* keynum : Index of the input_keybinds keybind. */ * @fn static void input_key(int keynum, double value, int kabs)
/* value : Value of keypress (defined above). */ *
/* abs : Whether or not it's an abs value (For those pesky joysticks. */ * @brief Run the input command.
/* ===================================================================== */ * @param keynum The index of the keybind.
* @param value The value of the keypress (defined above).
* @param abs Whether or not it's an absolute value (for the joystick).
*/
#define KEY(s) (strcmp(input_keybinds[keynum]->name, s)==0) #define KEY(s) (strcmp(input_keybinds[keynum]->name, s)==0)
#define INGAME() (!toolkit) #define INGAME() (!toolkit)
/* We won't be having any more funny stuff from VLack.. */
#define NOHYP() \ #define NOHYP() \
(player && !pilot_isFlag(player, PILOT_HYP_PREP) && \ (player && !pilot_isFlag(player, PILOT_HYP_PREP) && \
!pilot_isFlag(player, PILOT_HYP_BEGIN) && \ !pilot_isFlag(player, PILOT_HYP_BEGIN) && \
@ -200,13 +232,13 @@ static void input_key(int keynum, double value, int kabs) {
} }
/* Targetting. */ /* Targetting. */
else if(INGAME() && KEY("target")) { else if(INGAME() && KEY("target")) {
if(value == KEY_PRESS) player_target = pilot_getNextID(player_target); if(value == KEY_PRESS) player_targetNext();
} }
else if(INGAME() && KEY("target_nearest")) { else if(INGAME() && KEY("target_nearest")) {
if(value == KEY_PRESS) player_target = pilot_getNearestPilot(player); if(value == KEY_PRESS) player_targetNearest();
} }
else if(INGAME() && KEY("target_hostile")) { else if(INGAME() && KEY("target_hostile")) {
if(value == KEY_PRESS) player_target = pilot_getNearestHostile(); if(value == KEY_PRESS) player_targetHostile();
} }
/* Face the target. */ /* Face the target. */
else if(KEY("face")) { else if(KEY("face")) {
@ -349,9 +381,15 @@ static void input_keyup(SDLKey key) {
} }
} }
/* Global input. */
/* Just seperates the event types. */ /**
* @fn void input_handle(SDL_Event* event)
*
* @brief Handle global input.
*
* Basically seperates the event types.
* @param event Incoming SDL_Event.
*/
void input_handle(SDL_Event* event) { void input_handle(SDL_Event* event) {
/* Pause the game if it is unfocused. */ /* Pause the game if it is unfocused. */
if(event->type == SDL_ACTIVEEVENT) { if(event->type == SDL_ACTIVEEVENT) {

View File

@ -1,3 +1,9 @@
/**
* @file pilot.c
*
* @brief Handles the pilot stuff.
*/
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -43,8 +43,9 @@
#define TARGET_WIDTH 128 /**< Width of target graphics. */ #define TARGET_WIDTH 128 /**< Width of target graphics. */
#define TARGET_HEIGHT 96 /**< Height of target graphics. */ #define TARGET_HEIGHT 96 /**< Height of target graphics. */
#define PLAYER_RESERVED_CHANNELS 4 /**< Number of channels to reserve for player sounds. */ #define PLAYER_RESERVED_CHANNELS 6 /**< Number of channels to reserve for player sounds. */
#define PLAYER_CHANNEL 0 /**< Player channel. */ #define PLAYER_ENGINE_CHANNEL 9 /**< Player channel for engine noises. */
#define PLAYER_GUI_CHANNEL 9 /**< Player channel. */
/* Player stuff. */ /* Player stuff. */
Pilot* player = NULL; /**< The player. */ Pilot* player = NULL; /**< The player. */
@ -156,8 +157,7 @@ static void player_newMake(void);
static void player_newShipMake(char* name); static void player_newShipMake(char* name);
/* Sound. */ /* Sound. */
static void player_initSound(void); static void player_initSound(void);
static void player_playSound(int sound, int once); /*static void player_stopSound(void) */
static void player_stopSound(void);
/* Gui. */ /* Gui. */
static void rect_parse(const xmlNodePtr parent, static void rect_parse(const xmlNodePtr parent,
double* x, double* y, double* w, double* h); double* x, double* y, double* w, double* h);
@ -479,7 +479,8 @@ static void player_initSound(void) {
if(player_soundReserved) return; if(player_soundReserved) return;
sound_reserve(PLAYER_RESERVED_CHANNELS); sound_reserve(PLAYER_RESERVED_CHANNELS);
sound_createGroup(PLAYER_CHANNEL, 0, PLAYER_RESERVED_CHANNELS); sound_createGroup(PLAYER_ENGINE_CHANNEL, 0, 1); /* Channel for engine noises. */
sound_createGroup(PLAYER_GUI_CHANNEL, 1, PLAYER_RESERVED_CHANNELS-1);
player_soundReserved = 1; player_soundReserved = 1;
} }
@ -490,18 +491,20 @@ static void player_initSound(void) {
* @param sound ID of the sound to play. * @param sound ID of the sound to play.
* @param once Play only once? * @param once Play only once?
*/ */
static void player_playSound(int sound, int once) { void player_playSound(int sound, int once) {
sound_playGroup(PLAYER_CHANNEL, sound, once); sound_playGroup(PLAYER_GUI_CHANNEL, sound, once);
} }
#if 0
/** /**
* @fn static void player_stopSound(void) * @fn static void player_stopSound(void)
* *
* @brief Stop playing player sounds. * @brief Stop playing player sounds.
*/ */
static void player_stopSound(void) { static void player_stopSound(void) {
sound_stopGroup(PLAYER_CHANNEL); sound_stopGroup(PLAYER_GUI_CHANNEL);
} }
#endif
/** /**
* @fn void player_message(const char* fmt, ...) * @fn void player_message(const char* fmt, ...)
@ -1010,7 +1013,12 @@ static void gui_renderBar(const glColour* c, const Rect* r, const double w) {
glEnd(); glEnd();
} }
/* Init GUI. */ /**
* @fn int gui_init(void)
*
* @brief Initialize the GUI system.
* @return 0 on success.
*/
int gui_init(void) { int gui_init(void) {
/* Set graphics to NULL. */ /* Set graphics to NULL. */
gui.gfx_frame = NULL; gui.gfx_frame = NULL;
@ -1024,10 +1032,21 @@ int gui_init(void) {
gui.msg.y = 30; gui.msg.y = 30;
msg_stack = calloc(msg_max, sizeof(Msg)); msg_stack = calloc(msg_max, sizeof(Msg));
if(msg_stack == NULL) {
ERR("Out of memory!");
return -1;
}
return 0; return 0;
} }
/* Attempts to load the actual gui. */ /**
* @fn int gui_load(const char* name)
*
* @brief Attempt to load the actual GUI.
* @brief name Name of the GUI to load.
* @brief 0 on success.
*/
int gui_load(const char* name) { int gui_load(const char* name) {
uint32_t bufsize; uint32_t bufsize;
char* buf = pack_readfile(DATA, GUI_DATA, &bufsize); char* buf = pack_readfile(DATA, GUI_DATA, &bufsize);
@ -1265,7 +1284,11 @@ static int gui_parse(const xmlNodePtr parent, const char* name) {
} }
#undef RELATIVIZE #undef RELATIVIZE
/* Free the GUI. */ /**
* @fn void gui_free(void)
*
* @brief Free the GUI.
*/
void gui_free(void) { void gui_free(void) {
if(gui.gfx_frame) gl_freeTexture(gui.gfx_frame); if(gui.gfx_frame) gl_freeTexture(gui.gfx_frame);
if(gui.gfx_targetPilot) gl_freeTexture(gui.gfx_targetPilot); if(gui.gfx_targetPilot) gl_freeTexture(gui.gfx_targetPilot);
@ -1274,8 +1297,12 @@ void gui_free(void) {
free(msg_stack); free(msg_stack);
} }
/* Used in pilot.c */ /**
/* Basically uses keyboard input instead of AI input. */ * @fn void player_think(Pilot* pplayer)
*
* @brief Basically uses keyboard input instead of AI input. Used in pilot.c.
* @param pplayer Player to think.
*/
void player_think(Pilot* pplayer) { void player_think(Pilot* pplayer) {
/* Last I checked, the dead didn't think.. */ /* Last I checked, the dead didn't think.. */
if(pilot_isFlag(pplayer, PILOT_DEAD)) { if(pilot_isFlag(pplayer, PILOT_DEAD)) {
@ -1330,7 +1357,16 @@ void player_think(Pilot* pplayer) {
} }
/* Modify the radar resolution. */ /*
* For use in keybindings.
*/
/**
* @fn void player_setRadarRel(int mod)
*
* @brief Modify the radar resolution.
* @param mod Number of intervals to jump (up or down).
*/
void player_setRadarRel(int mod) { void player_setRadarRel(int mod) {
gui.radar.res += mod * RADAR_RES_INTERVAL; gui.radar.res += mod * RADAR_RES_INTERVAL;
if(gui.radar.res > RADAR_RES_MAX) gui.radar.res = RADAR_RES_MAX; if(gui.radar.res > RADAR_RES_MAX) gui.radar.res = RADAR_RES_MAX;
@ -1339,7 +1375,11 @@ void player_setRadarRel(int mod) {
player_message("Radar set to %dx.", (int)gui.radar.res); player_message("Radar set to %dx.", (int)gui.radar.res);
} }
/* Get the next secondary weapon. */ /**
* @fn void player_secondaryNext(void)
*
* @brief Get the next secondary weapon.
*/
void player_secondaryNext(void) { void player_secondaryNext(void) {
int i = 0; int i = 0;
@ -1364,7 +1404,11 @@ void player_secondaryNext(void) {
pilot_setAmmo(player); pilot_setAmmo(player);
} }
/* Cycle through planet targets. */ /**
* @fn void player_targetPlanet(void)
*
* @brief Cycle through planet targets.
*/
void player_targetPlanet(void) { void player_targetPlanet(void) {
hyperspace_target = -1; hyperspace_target = -1;
player_rmFlag(PLAYER_LANDACK); player_rmFlag(PLAYER_LANDACK);
@ -1382,7 +1426,11 @@ void player_targetPlanet(void) {
planet_target = -1; planet_target = -1;
} }
/* Attempt to land or target closest planet if no land target. */ /**
* fn void player_land(void)
*
* @brief Try to land or target closest planet if no land target.
*/
void player_land(void) { void player_land(void) {
int i; int i;
int tp; int tp;
@ -1450,6 +1498,11 @@ void player_land(void) {
} }
} }
/**
* @fn void player_targetHyperspace(void)
*
* @brief Get a hyperspace target.
*/
void player_targetHyperspace(void) { void player_targetHyperspace(void) {
planet_target = -1; /* Remove planet target. */ planet_target = -1; /* Remove planet target. */
player_rmFlag(PLAYER_LANDACK); /* Get rid of landing permission. */ player_rmFlag(PLAYER_LANDACK); /* Get rid of landing permission. */
@ -1460,15 +1513,20 @@ void player_targetHyperspace(void) {
hyperspace_target = -1; hyperspace_target = -1;
} }
/* Actually attempt to jump into hyperspace. */ /**
* @fn void player_jump(void)
*
* @brief Actually attempt to jump in hyperspace.
*/
void player_jump(void) { void player_jump(void) {
int i;
if((hyperspace_target == -1) || if((hyperspace_target == -1) ||
pilot_isFlag(player, PILOT_HYP_PREP) || pilot_isFlag(player, PILOT_HYP_PREP) ||
pilot_isFlag(player, PILOT_HYP_BEGIN) || pilot_isFlag(player, PILOT_HYP_BEGIN) ||
pilot_isFlag(player, PILOT_HYPERSPACE)) pilot_isFlag(player, PILOT_HYPERSPACE))
return; return;
int i = space_hyperspace(player); i = space_hyperspace(player);
if(i == -1) if(i == -1)
player_message("You are too close to gravity centers to initiate hyperspace."); player_message("You are too close to gravity centers to initiate hyperspace.");
@ -1480,7 +1538,11 @@ void player_jump(void) {
player_message("Preparing for hyperspace."); player_message("Preparing for hyperspace.");
} }
/* Player actually broke hyperspace (Let's enter a new system). */ /**
* @fn void player_brokeHyperspace(void)
*
* @brief Player actually broke hyperspace (entering new system).
*/
void player_brokeHyperspace(void) { void player_brokeHyperspace(void) {
unsigned int tl, th; unsigned int tl, th;
@ -1514,7 +1576,12 @@ void player_brokeHyperspace(void) {
player_message("BANG!"); player_message("BANG!");
} }
/* Make the player face her hyperspace target. */ /**
* @fn double player_faceHyperspace(void)
*
* @brief Make player face her hyperspace target.
* @return direction to face.
*/
double player_faceHyperspace(void) { double player_faceHyperspace(void) {
double a; double a;
a = ANGLE(systems_stack[cur_system->jumps[hyperspace_target]].pos.x - a = ANGLE(systems_stack[cur_system->jumps[hyperspace_target]].pos.x -
@ -1525,40 +1592,109 @@ double player_faceHyperspace(void) {
return pilot_face(player, a); return pilot_face(player, a);
} }
/* Activate afterburner. */ /**
* @fn void player_afterburn(void)
*
* @brief Activate the afterburner.
*/
void player_afterburn(void) { void player_afterburn(void) {
/* TODO: Fancy effects. */ /* TODO: Fancy effects. */
if((player != NULL) && (player->afterburner != NULL)) { if((player != NULL) && (player->afterburner != NULL)) {
player_setFlag(PLAYER_AFTERBURNER); player_setFlag(PLAYER_AFTERBURNER);
pilot_setFlag(player, PILOT_AFTERBURNER); pilot_setFlag(player, PILOT_AFTERBURNER);
spfx_shake(player->afterburner->outfit->u.afb.rumble * SHAKE_MAX); spfx_shake(player->afterburner->outfit->u.afb.rumble * SHAKE_MAX);
player_playSound(player->afterburner->outfit->u.afb.sound, 0); sound_stopGroup(PLAYER_ENGINE_CHANNEL);
sound_playGroup(PLAYER_ENGINE_CHANNEL,
player->afterburner->outfit->u.afb.sound, 0);
} }
} }
/**
* @fn void player_afterburnOver(void)
*
* @brief Deactivate the afterburner.
*/
void player_afterburnOver(void) { void player_afterburnOver(void) {
if((player != NULL) && (player->afterburner != NULL)) { if((player != NULL) && (player->afterburner != NULL)) {
player_rmFlag(PLAYER_AFTERBURNER); player_rmFlag(PLAYER_AFTERBURNER);
pilot_rmFlag(player, PILOT_AFTERBURNER); pilot_rmFlag(player, PILOT_AFTERBURNER);
player_stopSound(); sound_stopGroup(PLAYER_ENGINE_CHANNEL);
} }
} }
/* Start accelerating. */ /**
* @fn void player_accel(double acc)
*
* @brief Start accelerating.
* @param acc How much thrust should be applied of maximum (0 - 1).
*/
void player_accel(double acc) { void player_accel(double acc) {
if(player != NULL) { if(player != NULL) {
player_acc = acc; player_acc = acc;
player_playSound(player->ship->sound, 0); sound_stopGroup(PLAYER_ENGINE_CHANNEL);
sound_playGroup(PLAYER_ENGINE_CHANNEL,
player->ship->sound, 0);
} }
} }
/**
* @fn void player_accelOver(void)
*
* @brief Done accelerating.
*/
void player_accelOver(void) { void player_accelOver(void) {
player_acc = 0; player_acc = 0;
player_stopSound(); sound_stopGroup(PLAYER_ENGINE_CHANNEL);
} }
/* Take a screenshot. */ /**
static int screenshot_cur = 0; * @fn void player_targetHostile(void)
*
* @brief Target the nearest hostile enemy to the player.
*/
void player_targetHostile(void) {
unsigned int tp;
int i;
double d, td;
tp = PLAYER_ID;
d = 0;
for(i = 0; i < pilot_nstack; i++)
if(pilot_isFlag(pilot_stack[i], PILOT_HOSTILE) ||
areEnemies(FACTION_PLAYER, pilot_stack[i]->faction)) {
td = vect_dist(&pilot_stack[i]->solid->pos, &player->solid->pos);
if(!pilot_isDisabled(pilot_stack[i]) && ((tp == PLAYER_ID) || (td < d))) {
d = td;
tp = pilot_stack[i]->id;
}
}
player_target = tp;
}
/**
* @fn void player_targetNext(void)
*
* @brief Cycles to next target.
*/
void player_targetNext(void) {
player_target = pilot_getNextID(player_target);
}
/**
* @fn player_targetNearest(void)
*
* @brief Player targets nearest pilot.
*/
void player_targetNearest(void) {
player_target = pilot_getNearestPilot(player);
}
/**
* @fn void player_screenshot(void)
*
* @brief Take a screenshot.
*/
static int screenshot_cur = 0; /**< Current screenshot at. */
void player_screenshot(void) { void player_screenshot(void) {
FILE* fp; FILE* fp;
int done; int done;
@ -1594,13 +1730,21 @@ void player_screenshot(void) {
gl_screenshot(filename); gl_screenshot(filename);
} }
/* Player go pwned. */ /**
* @fn void player_dead(void)
*
* @brief Player got killed.
*/
void player_dead(void) { void player_dead(void) {
gui_xoff = 0.; gui_xoff = 0.;
gui_yoff = 0.; gui_yoff = 0.;
} }
/* Player blew up in a nice fireball. */ /**
* @fn void player_destroyed(void)
*
* @brief Player blew up in a nice fireball.
*/
void player_destroyed(void) { void player_destroyed(void) {
if(player_isFlag(PLAYER_DESTROYED)) return; if(player_isFlag(PLAYER_DESTROYED)) return;
@ -1610,8 +1754,14 @@ void player_destroyed(void) {
player_timer = SDL_GetTicks() + 5000; player_timer = SDL_GetTicks() + 5000;
} }
/* Return a buffer with all the ships names, or none if there */ /**
/* aren't any. */ * @fn char** player_ships(int* nships)
*
* @brief Return a buffer with all the players ship names
* or "None" if there are no ships.
* @param nships Stores the number of ships.
* @return Freshly allocated array with allocated ship names.
*/
char** player_ships(int* nships) { char** player_ships(int* nships) {
int i; int i;
char** shipnames; char** shipnames;
@ -1630,7 +1780,12 @@ char** player_ships(int* nships) {
return shipnames; return shipnames;
} }
/* Return the amount of ships player has in storage. */ /**
* @fn int player_nships(void)
*
* @brief Get the ammount of ships player has in storage.
* @return The number of ships the player has.
*/
int player_nships(void) { int player_nships(void) {
return player_nstack; return player_nstack;
} }

View File

@ -48,6 +48,7 @@ void player_message(const char* fmt, ...);
void player_clear(void); void player_clear(void);
void player_warp(const double x, const double y); void player_warp(const double x, const double y);
const char* player_rating(void); const char* player_rating(void);
void player_playSound(int sound, int once);
/* Cargo. */ /* Cargo. */
int player_outfitOwned(const char* outfitname); int player_outfitOwned(const char* outfitname);
int player_cargoOwned(const char* commodityname); int player_cargoOwned(const char* commodityname);
@ -66,6 +67,9 @@ void player_missionFinished(int id);
int player_missionAlreadyDone(int id); int player_missionAlreadyDone(int id);
/* Keybind actions. */ /* Keybind actions. */
void player_targetHostile(void);
void player_targetNext(void);
void player_targetNearest(void);
void player_setRadarRel(int mod); void player_setRadarRel(int mod);
void player_secondaryNext(void); void player_secondaryNext(void);
void player_targetPlanet(void); void player_targetPlanet(void);

View File

@ -381,6 +381,10 @@ int sound_playGroup(int group, int sound, int once) {
if(sound_disabled) return 0; if(sound_disabled) return 0;
channel = Mix_GroupAvailable(group); channel = Mix_GroupAvailable(group);
if(channel == -1) {
WARN("Group '%d' has no free channels!", group);
return -1;
}
ret = Mix_PlayChannel(channel, sound_list[sound].buffer, ret = Mix_PlayChannel(channel, sound_list[sound].buffer,
(once == 0) ? -1 : 0); (once == 0) ? -1 : 0);
@ -403,6 +407,6 @@ int sound_playGroup(int group, int sound, int once) {
void sound_stopGroup(int group) { void sound_stopGroup(int group) {
if(sound_disabled) return; if(sound_disabled) return;
Mix_FadeOutGroup(group, 100); Mix_HaltGroup(group);
} }