Got Instruments working and fixed several small leaks. Currently mostly seeing occasional leaks of OOWeakReferences to ships (but the ships themselves aren't leaked and OOWeakReferences are only 8 bytes.) Cobbled together a class for handling groups of sources for related sounds, so that e.g. the number of simultanous scrape sounds is limited. Moved bits of player launching logic from pollDockedControls: to leaveDock: (which is also called from other places).

git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@1465 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2008-03-08 17:16:10 +00:00
parent fe418babea
commit 3f74d1b923
26 changed files with 732 additions and 347 deletions

View File

@ -26,7 +26,7 @@ endif
OBJC_PROGRAM_NAME = oolite
oolite_C_FILES = legacy_random.c strlcpy.c OOTCPStreamDecoder.c
oolite_OBJC_FILES = OOCocoa.m Comparison.m AI.m DustEntity.m Entity.m GameController.m GuiDisplayGen.m HeadUpDisplay.m main.m MyOpenGLView.m OpenGLSprite.m ParticleEntity.m PlanetEntity.m PlayerEntityLegacyScriptEngine.m PlayerEntityContracts.m PlayerEntityControls.m PlayerEntityLoadSave.m PlayerEntitySound.m PlayerEntity.m ResourceManager.m RingEntity.m ShipEntityAI.m ShipEntity.m SkyEntity.m StationEntity.m Universe.m OOSound.m SDLMusic.m NSFileManagerOOExtensions.m JoystickHandler.m PlayerEntityStickMapper.m OOBasicSoundReferencePoint.m OOBasicSoundSource.m OOCharacter.m OOTrumble.m WormholeEntity.m NSScannerOOExtensions.m OOXMLExtensions.m NSMutableDictionaryOOExtensions.m Geometry.m Octree.m CollisionRegion.m OOColor.m OOLogging.m OOCacheManager.m OOCache.m OOStringParsing.m OOCollectionExtractors.m OOVector.m OOMatrix.m OOQuaternion.m OOVoxel.m OOTriangle.m OOPListParsing.m OOFastArithmetic.m OOTextureScaling.m OOConstToString.m OOScript.m OOJSScript.m OOJavaScriptEngine.m OOPListScript.m NSStringOOExtensions.m PlayerEntityScriptMethods.m OOWeakReference.m OOJSEntity.m EntityOOJavaScriptExtensions.m OOJSQuaternion.m OOMaterial.m OOShaderMaterial.m OOShaderProgram.m OOShaderUniform.m OOTexture.m OOTextureLoader.m OOPNGTextureLoader.m OOOpenGLExtensionManager.m OOBasicMaterial.m OOSingleTextureMaterial.m OOCPUInfo.m OOSelfDrawingEntity.m OOEntityWithDrawable.m OODrawable.m OOJSVector.m OOMesh.m OOOpenGL.m OOGraphicsResetManager.m OOProbabilisticTextureManager.m OODebugGLDrawing.m OOShaderUniformMethodType.m OOAsyncQueue.m TextureStore.m OOOXPVerifier.m OOOXPVerifierStage.m OOFileScannerVerifierStage.m OOCheckRequiresPListVerifierStage.m OOCheckDemoShipsPListVerifierStage.m OOCheckEquipmentPListVerifierStage.m OOTextureVerifierStage.m OOModelVerifierStage.m OOCheckShipDataPListVerifierStage.m OOPListSchemaVerifier.m OOJSShip.m OOJSPlayer.m OOJSCall.m OOJSStation.m OOJSSystem.m OOLegacyEventHandlerScript.m OOJSOolite.m OORoleSet.m OOJSGlobal.m OOJSMissionVariables.m OOJSMission.m OOPriorityQueue.m OOScriptTimer.m OOJSTimer.m OOJSClock.m OODebugSupport.m OODebugMonitor.m OOJSConsole.m OODebugTCPConsoleClient.m OOTCPStreamDecoderAbstractionLayer.m OOEntityFilterPredicate.m OOJSPlanet.m OOJSWorldScripts.m OOJSSun.m NSThreadOOExtensions.m OOEncodingConverter.m OOJSSound.m OOJSSoundSource.m OOMusicController.m OOLogHeader.m OOJSSpecialFunctions.m OOSpatialReference.m OOSkyDrawable.m OOFilteringEnumerator.m
oolite_OBJC_FILES = OOCocoa.m Comparison.m AI.m DustEntity.m Entity.m GameController.m GuiDisplayGen.m HeadUpDisplay.m main.m MyOpenGLView.m OpenGLSprite.m ParticleEntity.m PlanetEntity.m PlayerEntityLegacyScriptEngine.m PlayerEntityContracts.m PlayerEntityControls.m PlayerEntityLoadSave.m PlayerEntitySound.m PlayerEntity.m ResourceManager.m RingEntity.m ShipEntityAI.m ShipEntity.m SkyEntity.m StationEntity.m Universe.m OOSound.m SDLMusic.m NSFileManagerOOExtensions.m JoystickHandler.m PlayerEntityStickMapper.m OOBasicSoundReferencePoint.m OOBasicSoundSource.m OOCharacter.m OOTrumble.m WormholeEntity.m NSScannerOOExtensions.m OOXMLExtensions.m NSMutableDictionaryOOExtensions.m Geometry.m Octree.m CollisionRegion.m OOColor.m OOLogging.m OOCacheManager.m OOCache.m OOStringParsing.m OOCollectionExtractors.m OOVector.m OOMatrix.m OOQuaternion.m OOVoxel.m OOTriangle.m OOPListParsing.m OOFastArithmetic.m OOTextureScaling.m OOConstToString.m OOScript.m OOJSScript.m OOJavaScriptEngine.m OOPListScript.m NSStringOOExtensions.m PlayerEntityScriptMethods.m OOWeakReference.m OOJSEntity.m EntityOOJavaScriptExtensions.m OOJSQuaternion.m OOMaterial.m OOShaderMaterial.m OOShaderProgram.m OOShaderUniform.m OOTexture.m OOTextureLoader.m OOPNGTextureLoader.m OOOpenGLExtensionManager.m OOBasicMaterial.m OOSingleTextureMaterial.m OOCPUInfo.m OOSelfDrawingEntity.m OOEntityWithDrawable.m OODrawable.m OOJSVector.m OOMesh.m OOOpenGL.m OOGraphicsResetManager.m OOProbabilisticTextureManager.m OODebugGLDrawing.m OOShaderUniformMethodType.m OOAsyncQueue.m TextureStore.m OOOXPVerifier.m OOOXPVerifierStage.m OOFileScannerVerifierStage.m OOCheckRequiresPListVerifierStage.m OOCheckDemoShipsPListVerifierStage.m OOCheckEquipmentPListVerifierStage.m OOTextureVerifierStage.m OOModelVerifierStage.m OOCheckShipDataPListVerifierStage.m OOPListSchemaVerifier.m OOJSShip.m OOJSPlayer.m OOJSCall.m OOJSStation.m OOJSSystem.m OOLegacyEventHandlerScript.m OOJSOolite.m OORoleSet.m OOJSGlobal.m OOJSMissionVariables.m OOJSMission.m OOPriorityQueue.m OOScriptTimer.m OOJSTimer.m OOJSClock.m OODebugSupport.m OODebugMonitor.m OOJSConsole.m OODebugTCPConsoleClient.m OOTCPStreamDecoderAbstractionLayer.m OOEntityFilterPredicate.m OOJSPlanet.m OOJSWorldScripts.m OOJSSun.m NSThreadOOExtensions.m OOEncodingConverter.m OOJSSound.m OOJSSoundSource.m OOMusicController.m OOLogHeader.m OOJSSpecialFunctions.m OOSpatialReference.m OOSkyDrawable.m OOFilteringEnumerator.m OOSoundSourcePool.m
include $(GNUSTEP_MAKEFILES)/objc.make
include GNUmakefile.postamble

View File

@ -514,6 +514,8 @@
1AC775E20C2DD4E900ECFF3B /* OODebugGLDrawing.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AC775E00C2DD4E900ECFF3B /* OODebugGLDrawing.h */; };
1AC775E30C2DD4E900ECFF3B /* OODebugGLDrawing.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AC775E10C2DD4E900ECFF3B /* OODebugGLDrawing.m */; };
1AC973FA0C9847850010C42B /* pirate-victim-roles.plist in Copy Config */ = {isa = PBXBuildFile; fileRef = 1AC973F90C9847850010C42B /* pirate-victim-roles.plist */; };
1ACBF0AD0D82F79600CC005F /* OOSoundSourcePool.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACBF06F0D82DF9B00CC005F /* OOSoundSourcePool.h */; };
1ACBF0AE0D82F79800CC005F /* OOSoundSourcePool.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACBF0700D82DF9B00CC005F /* OOSoundSourcePool.m */; };
1ACE208F0D805F78009F6957 /* oolite-scarred-metal-specular.png in Resources */ = {isa = PBXBuildFile; fileRef = 1ACE208E0D805F78009F6957 /* oolite-scarred-metal-specular.png */; };
1ACEA3490C91507000C7CE97 /* OORoleSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACEA3470C91507000C7CE97 /* OORoleSet.h */; };
1ACEA34A0C91507000C7CE97 /* OORoleSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACEA3480C91507000C7CE97 /* OORoleSet.m */; };
@ -1026,7 +1028,7 @@
1A2315510B9C778400EF0852 /* trumblebox.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = trumblebox.png; sourceTree = "<group>"; };
1A2316DE0B9CFAD700EF0852 /* characters.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = characters.plist; sourceTree = "<group>"; };
1A2316DF0B9CFAD700EF0852 /* commodities.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = commodities.plist; sourceTree = "<group>"; };
1A2316E00B9CFAD700EF0852 /* customsounds.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = customsounds.plist; sourceTree = "<group>"; };
1A2316E00B9CFAD700EF0852 /* customsounds.plist */ = {isa = PBXFileReference; explicitFileType = text.plist; fileEncoding = 4; path = customsounds.plist; sourceTree = "<group>"; };
1A2316E10B9CFAD700EF0852 /* demoships.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = demoships.plist; sourceTree = "<group>"; };
1A2316E20B9CFAD700EF0852 /* descriptions.plist */ = {isa = PBXFileReference; explicitFileType = text.plist; fileEncoding = 4; path = descriptions.plist; sourceTree = "<group>"; };
1A2316E30B9CFAD700EF0852 /* equipment.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = equipment.plist; sourceTree = "<group>"; };
@ -1504,6 +1506,8 @@
1AC775E00C2DD4E900ECFF3B /* OODebugGLDrawing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OODebugGLDrawing.h; sourceTree = "<group>"; };
1AC775E10C2DD4E900ECFF3B /* OODebugGLDrawing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OODebugGLDrawing.m; sourceTree = "<group>"; };
1AC973F90C9847850010C42B /* pirate-victim-roles.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = "pirate-victim-roles.plist"; sourceTree = "<group>"; };
1ACBF06F0D82DF9B00CC005F /* OOSoundSourcePool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOSoundSourcePool.h; sourceTree = "<group>"; };
1ACBF0700D82DF9B00CC005F /* OOSoundSourcePool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOSoundSourcePool.m; sourceTree = "<group>"; };
1ACE208E0D805F78009F6957 /* oolite-scarred-metal-specular.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "oolite-scarred-metal-specular.png"; sourceTree = "<group>"; };
1ACEA3470C91507000C7CE97 /* OORoleSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OORoleSet.h; sourceTree = "<group>"; };
1ACEA3480C91507000C7CE97 /* OORoleSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OORoleSet.m; sourceTree = "<group>"; };
@ -2359,6 +2363,8 @@
1AAB9A960D779F3C00A9F424 /* OOCocoa.m */,
1A1616600D7DCFDC0094AE5B /* OOFilteringEnumerator.h */,
1A1616610D7DCFDC0094AE5B /* OOFilteringEnumerator.m */,
1ACBF06F0D82DF9B00CC005F /* OOSoundSourcePool.h */,
1ACBF0700D82DF9B00CC005F /* OOSoundSourcePool.m */,
);
name = Utilities;
sourceTree = "<group>";
@ -2810,6 +2816,7 @@
1A5218DA0D72EC21000865E9 /* OOSpatialReference.h in Headers */,
1A03658A0D7CA05000B5F46F /* OOSkyDrawable.h in Headers */,
1A1616620D7DCFDC0094AE5B /* OOFilteringEnumerator.h in Headers */,
1ACBF0AD0D82F79600CC005F /* OOSoundSourcePool.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -3161,6 +3168,7 @@
1AAB9A980D779F4500A9F424 /* OOCocoa.m in Sources */,
1A0365890D7CA05000B5F46F /* OOSkyDrawable.m in Sources */,
1A1616630D7DCFDC0094AE5B /* OOFilteringEnumerator.m in Sources */,
1ACBF0AE0D82F79800CC005F /* OOSoundSourcePool.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -1,84 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- list all possible custom sounds here -->
<!-- implemented: just the test sound -->
<key>[test]</key>
<string>buy.ogg</string>
<!-- unimplmented:
<key>[witch-blocked-by-@]</key>
<string>buy.ogg</string>
<key>[witch-no-fuel]</key>
<string>buy.ogg</string>
<key>[witch-no-target]</key>
<string>buy.ogg</string>
<key>[incoming-missile]</key>
<string>buy.ogg</string>
<key>[energy-low]</key>
<string>buy.ogg</string>
<key>[autopilot-on]</key>
<string>buy.ogg</string>
<key>[autopilot-off]</key>
<string>buy.ogg</string>
<key>[autopilot-cannot-dock-with-target]</key>
<string>buy.ogg</string>
<key>[autopilot-denied]</key>
<string>buy.ogg</string>
<key>[autopilot-out-of-range]</key>
<string>buy.ogg</string>
<key>[aegis-planet]</key>
<string>buy.ogg</string>
<key>[aegis-station]</key>
<string>buy.ogg</string>
<key>[mine-armed]</key>
<string>buy.ogg</string>
<key>[mine-launched]</key>
<string>buy.ogg</string>
<key>[missile-armed]</key>
<string>buy.ogg</string>
<key>[missile-locked-on]</key>
<string>buy.ogg</string>
<key>[missile-launched]</key>
<string>buy.ogg</string>
<key>[missile-safe]</key>
<string>buy.ogg</string>
<key>[weapon-overheat]</key>
<string>buy.ogg</string>
<key>[game-over]</key>
<string>buy.ogg</string>
<key>[witchdrive-malfunction]</key>
<string>buy.ogg</string>
<key>[ident-on]</key>
<string>buy.ogg</string>
<key>[ident-off]</key>
<string>buy.ogg</string>
<key>[ident-locked-on]</key>
<string>buy.ogg</string>
<key>[no-target-in-memory]</key>
<string>buy.ogg</string>
<key>[target-lost]</key>
<string>buy.ogg</string>
<key>[hold-full]</key>
<string>buy.ogg</string>
<key>[cargo-jettisoned]</key>
<string>buy.ogg</string>
<key>[hyperspace-countdown-begun]</key>
<string>buy.ogg</string>
<key>[galactic-hyperspace-countdown-begun]</key>
<string>buy.ogg</string>
<key>[hyperspace-countdown-aborted]</key>
<string>buy.ogg</string>
<key>[cloaking-device-on]</key>
<string>buy.ogg</string>
<key>[cloaking-device-off]</key>
<string>buy.ogg</string>
<key>[jump-mass-locked]</key>
<string>buy.ogg</string>
<key>[wormhole-created]</key>
<string>buy.ogg</string>
<key>[escape-pod-scooped]</key>
<string>buy.ogg</string>
-->
</dict>
</plist>
{
// Damage
"[player-hit-by-weapon]" = "hit.ogg"; // Hit by weapon
"[player-direct-hit]" = "hullbang.ogg"; // Hit by weapon while shield down ([player-hit-by-weapon] and [player-direct-hit] play at once)
"[player-scrape-damage]" = "hullbang.ogg"; // Touched another ship (or docking bay)
// Outgoing weapons fire
"[player-laser-hit]" = "laserhits.ogg";
"[player-laser-miss]" = "laser.ogg";
"[energy-bomb-fired]" = "bigbang.ogg";
// Warnings
"[hostile-warning]" = "warning.ogg";
"[alert-condition-red]" = "warning.ogg";
"[incoming-missile]" = "warning.ogg"; // Help, help, they're shooting at us
// "[energy-low]" = ""; // Energy below 25% - may occur repeatedly
"[autopilot-denied]" = "warning.ogg"; // Station refuses docking clearance
"[witchdrive-malfunction]" = "ecm.ogg"; // Misjump (3/4 witchjump malfunctions)
"[witchdrive-failure]" = "warning.ogg"; // Jump failed, internal damage (1/8 witchjump malfunctions; other 1/8 is fuel leak, see [fuel-leak])
"[fuel-leak]" = "warning.ogg";
// Tunnel effects
"[player-launch-from-station]" = "breakpattern.ogg";
"[player-dock-with-station]" = "breakpattern.ogg";
"[player-exit-witchspace]" = "breakpattern.ogg";
// ECM
"[player-fired-ecm]" = "ecm.ogg";
"[player-hit-by-ecm]" = "ecm.ogg";
"[game-over]" = "bigbang.ogg";
/* The following can also be overriden:
"[aegis-planet]" = "";
"[aegis-station]" = "";
"[autopilot-cannot-dock-with-target]" = "";
"[autopilot-off]" = "";
"[autopilot-on]" = "";
"[autopilot-out-of-range]" = "";
"[cargo-jettisoned]" = "";
"[cloaking-device-off]" = "";
"[cloaking-device-on]" = "";
"[escape-pod-scooped]" = "";
"[galactic-hyperspace-countdown-begun]" = "";
"[game-over]" = "";
"[hold-full]" = "";
"[hyperspace-countdown-aborted]" = "";
"[hyperspace-countdown-begun]" = "";
"[ident-locked-on]" = "";
"[ident-off]" = "";
"[ident-on]" = "";
"[incoming-missile]" = "";
"[jump-mass-locked]" = "";
"[mine-armed]" = "";
"[mine-launched]" = "";
"[missile-armed]" = "";
"[missile-launched]" = "";
"[missile-locked-on]" = "";
"[missile-safe]" = "";
"[no-target-in-memory]" = "";
"[target-lost]" = "";
"[weapon-overheat]" = "";
"[witch-blocked-by-@]" = "";
"[witch-no-fuel]" = "";
"[witch-no-target]" = "";
"[wormhole-created]" = "";
*/
}

View File

@ -69,7 +69,6 @@ SOFTWARE.
+ (id)sourceWithSound:(OOSound *)inSound;
- (id)initWithSound:(OOSound *)inSound;
- (id)init;
// These options should be set before playing. Effect of setting them while playing is undefined.
- (OOSound *)sound;

View File

@ -52,12 +52,6 @@ SOFTWARE.
#pragma mark NSObject
- (id)init
{
return [super init];
}
- (void)dealloc
{
[self stop];

View File

@ -168,7 +168,7 @@ static AI *sCurrentlyRunningAI = nil;
if ([aiStack count] > 32)
{
OOLog(@"ai.pushStateMachine.overflow", @"***** ERROR: AI stack overflow for %@ stack:\n%@", _owner, aiStack);
OOLog(@"ai.pushStateMachine.overflow", @"***** ERROR: AI stack overflow for %@ stack:\n%@", [_owner shortDescription], aiStack);
[NSException raise:@"OoliteException"
format:@"AI stack overflow for %@", _owner];
}

View File

@ -280,17 +280,9 @@ typedef enum
OOSound *beepSound;
OOSound *boopSound;
OOSound *weaponSound;
OOSound *weaponHitSound;
OOSound *missileSound;
OOSound *damageSound;
OOSound *scrapeDamageSound;
OOSound *destructionSound;
OOSound *breakPatternSound;
OOSound *ecmSound;
OOSound *buySound;
OOSound *sellSound;
OOSound *warningSound;
OOSound *afterburner1Sound;
OOSound *afterburner2Sound;
OOSound *witchAbortSound;

View File

@ -1773,7 +1773,6 @@ double scoopSoundPlayTime = 0.0;
else
{
ecm_in_operation = NO;
[self stopECMSound];
[UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[ecm-out-of-juice]") forCount:3.0];
}
if ([UNIVERSE getTime] > ecm_start_time + ECM_DURATION)
@ -2620,21 +2619,20 @@ double scoopSoundPlayTime = 0.0;
if ([ms isEqual:@"INCOMING_MISSILE"])
{
if (![UNIVERSE playCustomSound:@"[incoming-missile]"]) [warningSound play];
[self playIncomingMissile];
[UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[incoming-missile]") forCount:4.5];
}
if ([ms isEqual:@"ENERGY_LOW"])
{
[UNIVERSE playCustomSound:@"[energy-low]"];
[UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[energy-low]") forCount:6.0];
}
if ([ms isEqual:@"ECM"]) [self playECMSound];
if ([ms isEqual:@"ECM"]) [self playHitByECMSound];
if ([ms isEqual:@"DOCKING_REFUSED"]&&(status == STATUS_AUTOPILOT_ENGAGED))
{
if (![UNIVERSE playCustomSound:@"[autopilot-denied]"]) [warningSound play];
[self playDockingDenied];
[UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[autopilot-denied]") forCount:4.5];
autopilot_engaged = NO;
primaryTarget = NO_TARGET;
@ -2819,7 +2817,7 @@ double scoopSoundPlayTime = 0.0;
}
}
[UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[energy-bomb-activated]") forCount:4.5];
[destructionSound play];
[UNIVERSE playCustomSound:@"[energy-bomb-fired]"];
return YES;
}
@ -2971,14 +2969,7 @@ double scoopSoundPlayTime = 0.0;
d_forward = dot_product(rel_pos, v_forward);
if (damageSound)
{
#if 0
// FIXME: should use an OOSoundSource.
if ([damageSound isPlaying]) [damageSound stop];
[damageSound play];
#endif
}
[self playShieldHit];
// firing on an innocent ship is an offence
if ((other)&&(other->isShip))
@ -3017,14 +3008,7 @@ double scoopSoundPlayTime = 0.0;
{
internal_damage = ((ranrot_rand() & PLAYER_INTERNAL_DAMAGE_FACTOR) < amount); // base chance of damage to systems
energy -= amount;
if (scrapeDamageSound)
{
#if 0
// FIXME: should use an OOSoundSource.
if ([scrapeDamageSound isPlaying]) [scrapeDamageSound stop];
#endif
[scrapeDamageSound play];
}
[self playDirectHit];
ship_temperature += amount;
}
@ -3057,15 +3041,8 @@ double scoopSoundPlayTime = 0.0;
rel_pos = ent ? [ent position] : kZeroVector;
rel_pos = vector_subtract(rel_pos, position);
d_forward = dot_product(rel_pos, v_forward);
if (scrapeDamageSound)
{
#if 0
// FIXME: should use an OOSoundSource.
if ([scrapeDamageSound isPlaying]) [scrapeDamageSound stop];
#endif
[scrapeDamageSound play];
}
[self playScrapeDamage];
if (d_forward >= 0)
{
forward_shield -= amount;
@ -3464,7 +3441,6 @@ double scoopSoundPlayTime = 0.0;
[self moveForward:100.0];
[UNIVERSE playCustomSound:@"[game-over]"];
[destructionSound play];
flightSpeed = 160.0;
status = STATUS_DEAD;
@ -3533,7 +3509,7 @@ double scoopSoundPlayTime = 0.0;
[self setOrientation: kIdentityQuaternion]; // reset orientation to dock
[UNIVERSE set_up_break_pattern:position quaternion:orientation];
[self playBreakPattern];
[self playDockWithStation];
[station noteDockedShip:self];
dockedStation = station;
@ -3621,10 +3597,17 @@ double scoopSoundPlayTime = 0.0;
- (void) leaveDock:(StationEntity *)station
{
if (station == nil) return;
if (station == nil) return;
// ensure we've not left keyboard entry on
[[UNIVERSE gameView] allowStringInput: NO];
if (gui_screen == GUI_SCREEN_MISSION) [self doScriptEvent:@"missionScreenEnded"];
if (station == [UNIVERSE station])
{
legalStatus |= [UNIVERSE legal_status_of_manifest:shipCommodityData]; // 'leaving with those guns were you sir?'
}
[self loadCargoPods];
// clear the way
@ -3653,6 +3636,27 @@ double scoopSoundPlayTime = 0.0;
ship_clock_adjust = 600.0; // 10 minutes to leave dock
dockedStation = nil;
suppressAegisMessages = YES;
#if 0
// "Fix" for "simple" issue where space compass shows station with planet icon on launch.
// Has the slight unwanted side-effect of effectively giving the player an advanced compass.
if ([self checkForAegis] != AEGIS_NONE)
{
[self setCompassMode:COMPASS_MODE_STATION];
}
else
{
[self setCompassMode:COMPASS_MODE_PLANET];
}
#else
[self checkForAegis];
#endif
suppressAegisMessages = NO;
ident_engaged = NO;
[self playLaunchFromStation];
}
@ -3850,10 +3854,12 @@ double scoopSoundPlayTime = 0.0;
if (malfunc)
{
if (randf() > 0.5)
{
[self setFuelLeak:[NSString stringWithFormat:@"%f", (randf() + randf()) * 5.0]];
}
else
{
[warningSound play];
[self playWitchjumpFailure];
[self takeInternalDamage];
}
}
@ -3865,8 +3871,7 @@ double scoopSoundPlayTime = 0.0;
galaxy_coordinates.y += target_system_seed.b;
galaxy_coordinates.x /= 2;
galaxy_coordinates.y /= 2;
if (![UNIVERSE playCustomSound:@"[witchdrive-malfunction]"])
[self playECMSound];
[self playWitchjumpMisjump];
[UNIVERSE set_up_universe_from_misjump];
}
}
@ -3901,7 +3906,7 @@ double scoopSoundPlayTime = 0.0;
[UNIVERSE setDisplayCursor:NO];
[UNIVERSE setDisplayText:NO];
[UNIVERSE set_up_break_pattern:position quaternion:orientation];
[self playBreakPattern];
[self playExitWitchspace];
[self doScriptEvent:@"shipWillExitWitchspace"];
}

View File

@ -593,29 +593,7 @@ static NSTimeInterval time_last_frame;
{
if ([self fireMainWeapon])
{
if (target_laser_hit != NO_TARGET)
{
if (weaponHitSound)
{
#if 0
// FIXME: should use an OOSoundSource.
if ([weaponHitSound isPlaying])
[weaponHitSound stop];
#endif
[weaponHitSound play];
}
}
else
{
if (weaponSound)
{
#if 0
// FIXME: should use an OOSoundSource.
if ([weaponSound isPlaying]) [weaponSound stop];
#endif
[weaponSound play];
}
}
[self playLaserHit:target_laser_hit != NO_TARGET];
}
}
@ -784,7 +762,7 @@ static NSTimeInterval time_last_frame;
{
if ([self fireECM])
{
[self playECMSound];
[self playFiredECMSound];
[UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[ecm-on]") forCount:3.0];
}
}
@ -2595,41 +2573,16 @@ static BOOL toggling_music;
gameView = [UNIVERSE gameView];
if (([gameView isDown:gvFunctionKey1])||([gameView isDown:gvNumberKey1])) // look for the f1 key
{
// ensure we've not left keyboard entry on
[gameView allowStringInput: NO];
if (gui_screen == GUI_SCREEN_MISSION) [self doScriptEvent:@"missionScreenEnded"];
// FIXME: should this not be in leaveDock:? (Note: leaveDock: is also called from script method launchFromStation and -[StationEntity becomeExplosion]) -- Ahruman 20080308
[UNIVERSE setUpUniverseFromStation]; // launch!
if (!dockedStation)
dockedStation = [UNIVERSE station];
if (!dockedStation) dockedStation = [UNIVERSE station];
station = dockedStation; // leaveDock will clear dockedStation.
//don't autosave immediately after a load
if (station == [UNIVERSE station] && [UNIVERSE autoSaveNow]) [self autosavePlayer];
if ([UNIVERSE autoSave]) [UNIVERSE setAutoSaveNow:YES];
[self leaveDock:dockedStation];
[UNIVERSE setDisplayCursor:NO];
suppressAegisMessages = YES;
#if 0
// "Fix" for "simple" issue where space compass shows station with planet icon on launch.
// Has the slight unwanted side-effect of effectively giving the player an advanced compass.
if ([self checkForAegis] != AEGIS_NONE)
{
[self setCompassMode:COMPASS_MODE_STATION];
}
else
{
[self setCompassMode:COMPASS_MODE_PLANET];
}
#else
[self checkForAegis];
#endif
suppressAegisMessages = NO;
ident_engaged = NO;
[self doScriptEvent:@"shipWillLaunchFromStation" withArgument:station];
[self playBreakPattern];
}
}

View File

@ -24,6 +24,7 @@ MA 02110-1301, USA.
#import "PlayerEntityLegacyScriptEngine.h"
#import "PlayerEntityScriptMethods.h"
#import "PlayerEntitySound.h"
#import "GuiDisplayGen.h"
#import "Universe.h"
#import "ResourceManager.h"
@ -2065,8 +2066,7 @@ static int scriptRandomSeed = -1; // ensure proper random function
fuel_leak_rate = [value doubleValue];
if (fuel_leak_rate > 0)
{
if (![UNIVERSE playCustomSound:@"[fuel-leak]"])
[self warnAboutHostiles];
[self playFuelLeak];
[UNIVERSE addMessage:DESC(@"danger-fuel-leak") forCount:6];
OOLog(kOOLogNoteFuelLeak, @"FUEL LEAK activated!");
}
@ -2090,8 +2090,6 @@ static int scriptRandomSeed = -1; // ensure proper random function
- (void) launchFromStation
{
[self leaveDock:dockedStation];
[UNIVERSE setDisplayCursor:NO];
[breakPatternSound play];
}

View File

@ -36,20 +36,37 @@ enum
@interface PlayerEntity (Sound)
- (void)setUpSound;
- (void)destroySound;
- (void) setUpSound;
- (void) destroySound;
- (void)beep;
- (void)boop;
- (void)playInterfaceBeep:(unsigned)inInterfaceBeep;
- (BOOL)isBeeping;
- (void) beep;
- (void) boop;
- (void) playInterfaceBeep:(unsigned)inInterfaceBeep;
- (BOOL) isBeeping;
- (void)playECMSound;
- (void)stopECMSound;
- (void) playHitByECMSound;
- (void) playFiredECMSound;
- (void)playBreakPattern;
- (void) playLaunchFromStation;
- (void) playDockWithStation;
- (void) playExitWitchspace;
- (void)playHostileWarning;
- (void)playAlertConditionRed;
// Warning sounds
- (void) playHostileWarning;
- (void) playAlertConditionRed;
- (void) playIncomingMissile;
- (void) playEnergyLow;
- (void) playDockingDenied;
- (void) playWitchjumpFailure;
- (void) playWitchjumpMisjump;
- (void) playFuelLeak;
// Damage sounds
- (void) playShieldHit;
- (void) playDirectHit;
- (void) playScrapeDamage;
// Weapon sounds
- (void) playLaserHit:(BOOL)hit;
@end

View File

@ -25,6 +25,8 @@ MA 02110-1301, USA.
#import "PlayerEntitySound.h"
#import "OOSound.h"
#import "ResourceManager.h"
#import "Universe.h"
#import "OOSoundSourcePool.h"
/*
@ -36,26 +38,32 @@ MA 02110-1301, USA.
#define BEEP_MODE 1
// Sizes of sound source pools
enum
{
kWarningPoolSize = 2,
kWeaponPoolSize = 2,
kDamagePoolSize = 4
};
static OOSoundSourcePool *sWarningSoundPool;
static OOSoundSourcePool *sWeaponSoundPool;
static OOSoundSourcePool *sDamageSoundPool;
@implementation PlayerEntity (Sound)
- (void)setUpSound
- (void) setUpSound
{
[self destroySound];
beepSound = [[ResourceManager ooSoundNamed:@"beep.ogg" inFolder:@"Sounds"] retain];
boopSound = [[ResourceManager ooSoundNamed:@"boop.ogg" inFolder:@"Sounds"] retain];
weaponSound = [[ResourceManager ooSoundNamed:@"laser.ogg" inFolder:@"Sounds"] retain];
weaponHitSound = [[ResourceManager ooSoundNamed:@"laserhits.ogg" inFolder:@"Sounds"] retain];
missileSound = [[ResourceManager ooSoundNamed:@"missile.ogg" inFolder:@"Sounds"] retain];
damageSound = [[ResourceManager ooSoundNamed:@"hit.ogg" inFolder:@"Sounds"] retain];
scrapeDamageSound = [[ResourceManager ooSoundNamed:@"hullbang.ogg" inFolder:@"Sounds"] retain];
destructionSound = [[ResourceManager ooSoundNamed:@"bigbang.ogg" inFolder:@"Sounds"] retain];
breakPatternSound = [[ResourceManager ooSoundNamed:@"breakpattern.ogg" inFolder:@"Sounds"] retain];
ecmSound = [[ResourceManager ooSoundNamed:@"ecm.ogg" inFolder:@"Sounds"] retain];
buySound = [[ResourceManager ooSoundNamed:@"buy.ogg" inFolder:@"Sounds"] retain];
sellSound = [[ResourceManager ooSoundNamed:@"sell.ogg" inFolder:@"Sounds"] retain];
warningSound = [[ResourceManager ooSoundNamed:@"warning.ogg" inFolder:@"Sounds"] retain];
afterburner1Sound = [[ResourceManager ooSoundNamed:@"afterburner1.ogg" inFolder:@"Sounds"] retain];
afterburner2Sound = [[ResourceManager ooSoundNamed:@"afterburner2.ogg" inFolder:@"Sounds"] retain];
@ -67,36 +75,23 @@ MA 02110-1301, USA.
interfaceBeepSource = [[OOSoundSource alloc] init];
breakPatternSource = [[OOSoundSource alloc] init];
ecmSource = [[OOSoundSource alloc] init];
sWarningSoundPool = [[OOSoundSourcePool alloc] initWithCount:kWarningPoolSize minRepeatTime:0];
sWeaponSoundPool = [[OOSoundSourcePool alloc] initWithCount:kWeaponPoolSize minRepeatTime:0];
sDamageSoundPool = [[OOSoundSourcePool alloc] initWithCount:kDamagePoolSize minRepeatTime:0.1]; // Repeat time limit is to avoid playing a scrape sound every frame on glancing scrapes. This does limit the number of laser hits that can be played in a furrball, though; maybe lasers and scrapes should use different pools.
}
- (void)destroySound
- (void) destroySound
{
[beepSound release];
beepSound = nil;
[boopSound release];
boopSound = nil;
[weaponSound release];
weaponSound = nil;
[weaponHitSound release];
weaponHitSound = nil;
[damageSound release];
damageSound = nil;
[scrapeDamageSound release];
scrapeDamageSound = nil;
[destructionSound release];
destructionSound = nil;
[breakPatternSound release];
breakPatternSound = nil;
[ecmSound release];
ecmSound = nil;
[buySound release];
buySound = nil;
[sellSound release];
sellSound = nil;
[warningSound release];
warningSound = nil;
[afterburner1Sound release];
afterburner1Sound = nil;
[afterburner2Sound release];
@ -116,22 +111,29 @@ MA 02110-1301, USA.
ecmSource = nil;
[breakPatternSource release];
breakPatternSource = nil;
[sWarningSoundPool release];
sWarningSoundPool = nil;
[sWeaponSoundPool release];
sWeaponSoundPool = nil;
[sDamageSoundPool release];
sDamageSoundPool = nil;
}
- (void)beep
- (void) beep
{
[self playInterfaceBeep:kInterfaceBeep_Beep];
}
- (void)boop
- (void) boop
{
[self playInterfaceBeep:kInterfaceBeep_Boop];
}
- (void)playInterfaceBeep:(unsigned)inInterfaceBeep
- (void) playInterfaceBeep:(unsigned)inInterfaceBeep
{
OOSound *sound = nil;
@ -169,43 +171,118 @@ MA 02110-1301, USA.
}
- (BOOL)isBeeping
- (BOOL) isBeeping
{
return [interfaceBeepSource isPlaying];
}
- (void)playECMSound
- (void) playHitByECMSound
{
if (![ecmSource isPlaying]) [ecmSource playSound:ecmSound];
if (![ecmSource isPlaying]) [ecmSource playCustomSoundWithKey:@"[player-hit-by-ecm]"];
}
- (void)stopECMSound
- (void) playFiredECMSound
{
[ecmSource stop];
if (![ecmSource isPlaying]) [ecmSource playCustomSoundWithKey:@"[player-fired-ecm]"];
}
- (void)playBreakPattern
- (void) playLaunchFromStation
{
[breakPatternSource playSound:breakPatternSound];
[breakPatternSource playCustomSoundWithKey:@"[player-launch-from-station]"];
}
- (void)playHostileWarning
- (void) playDockWithStation
{
if (![warningSound isPlaying]) [warningSound play];
[breakPatternSource playCustomSoundWithKey:@"[player-dock-with-station]"];
}
- (void)playAlertConditionRed
- (void) playExitWitchspace
{
#if 0
// FIXME: should use an OOSoundSource.
if ([warningSound isPlaying]) [warningSound stop];
#endif
[warningSound play];
[breakPatternSource playCustomSoundWithKey:@"[player-exit-witchspace]"];
}
- (void) playHostileWarning
{
[sWarningSoundPool playSoundWithKey:@"[hostile-warning]" priority:1];
}
- (void) playAlertConditionRed
{
[sWarningSoundPool playSoundWithKey:@"[alert-condition-red]" priority:2];
}
- (void) playIncomingMissile
{
[sWarningSoundPool playSoundWithKey:@"[incoming-missile]" priority:3];
}
- (void) playEnergyLow
{
[sWarningSoundPool playSoundWithKey:@"[energy-low]" priority:0.5];
}
- (void) playDockingDenied
{
[sWarningSoundPool playSoundWithKey:@"[autopilot-denied]" priority:1];
}
- (void) playWitchjumpFailure
{
[sWarningSoundPool playSoundWithKey:@"[witchdrive-failure]" priority:1.5];
}
- (void) playWitchjumpMisjump
{
[sWarningSoundPool playSoundWithKey:@"[witchdrive-malfunction]" priority:1.5];
}
- (void) playFuelLeak
{
[sWarningSoundPool playSoundWithKey:@"[fuel-leak]" priority:0.5];
}
- (void) playShieldHit
{
[sDamageSoundPool playSoundWithKey:@"[player-hit-by-weapon]"];
}
- (void) playDirectHit
{
[sDamageSoundPool playSoundWithKey:@"[player-direct-hit]"];
}
- (void) playScrapeDamage
{
[sDamageSoundPool playSoundWithKey:@"[player-scrape-damage]"];
}
- (void) playLaserHit:(BOOL)hit
{
if (hit)
{
[sWeaponSoundPool playSoundWithKey:@"[player-laser-hit]" priority:1 expiryTime:0.05];
}
else
{
[sWeaponSoundPool playSoundWithKey:@"[player-laser-miss]" priority:1 expiryTime:0.05];
}
}
@end

View File

@ -293,7 +293,7 @@ MA 02110-1301, USA.
NSMutableArray *subEntities;
@private
OOWeakReference *subEntityTakingDamage; // frangible => subEntities can be damaged individually
OOWeakReference *_subEntityTakingDamage; // frangible => subEntities can be damaged individually
}
// ship brains

View File

@ -465,7 +465,7 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change
[octree autorelease];
[subEntityTakingDamage release];
[self setSubEntityTakingDamage:nil];
[super dealloc];
}
@ -556,26 +556,16 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change
- (ShipEntity *) subEntityTakingDamage
{
ShipEntity *result = [subEntityTakingDamage weakRefUnderlyingObject];
ShipEntity *result = [_subEntityTakingDamage weakRefUnderlyingObject];
#ifndef NDEBUG
// Sanity check - there have been problems here, see fireLaserShotInDirection:
if (result != nil)
{
if (![result isShip] || ![self hasSubEntity:result])
{
OOLog(@"ship.subentity.sanityCheck.failed", @"***** VALIDATION ERROR: Subentity taking damage (%@) for ship %@ is not a ship or is not a subentity of the owner. This is an internal error, please report it.", [result shortDescription], [self shortDescription]);
result = nil;
}
}
// -parentEntity will take care of reporting insanity.
if ([result parentEntity] != self) result = nil;
#endif
// Clear the weakref if the subentity is dead
if (result == nil)
{
[subEntityTakingDamage release];
subEntityTakingDamage = nil;
}
// Clear the weakref if the subentity is dead.
if (result == nil) [self setSubEntityTakingDamage:nil];
return result;
}
@ -583,12 +573,25 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change
- (void) setSubEntityTakingDamage:(ShipEntity *)sub
{
// Set subentityTakingDamage only if sub is 1. one of ours and 2. a ship (not a flasher or exhaust).
if ([sub isShip] && [self hasSubEntity:sub])
#ifndef NDEBUG
// Sanity checks: sub must be a ship subentity of self, or nil.
if (sub != nil)
{
[subEntityTakingDamage release];
subEntityTakingDamage = [sub weakRetain];
if (![self hasSubEntity:sub])
{
OOLog(@"ship.subentity.sanityCheck.failed.deatails", @"Attempt to set subentity taking damage of %@ to %@, which is not a subentity.", [self shortDescription], sub);
sub = nil;
}
if (![sub isShip])
{
OOLog(@"ship.subentity.sanityCheck.failed", @"Attempt to set subentity taking damage of %@ to %@, which is not a ship.", [self shortDescription], sub);
sub = nil;
}
}
#endif
[_subEntityTakingDamage release];
_subEntityTakingDamage = [sub weakRetain];
}
@ -4023,11 +4026,7 @@ static GLfloat mascem_color2[4] = { 0.4, 0.1, 0.4, 1.0}; // purple
- (void)subEntityDied:(ShipEntity *)sub
{
if ([subEntityTakingDamage weakRefUnderlyingObject] == sub)
{
[subEntityTakingDamage release];
subEntityTakingDamage = nil;
}
if ([self subEntityTakingDamage] == sub) [self setSubEntityTakingDamage:nil];
[sub setOwner:nil];
[subEntities removeObject:sub];
@ -4040,11 +4039,7 @@ static GLfloat mascem_color2[4] = { 0.4, 0.1, 0.4, 1.0}; // purple
unsigned i, count;
id element;
if ([subEntityTakingDamage weakRefUnderlyingObject] == sub)
{
[subEntityTakingDamage release];
subEntityTakingDamage = nil;
}
if ([self subEntityTakingDamage] == sub) [self setSubEntityTakingDamage:nil];
if ([self hasSubEntity:sub])
{

View File

@ -59,8 +59,6 @@ SOFTWARE.
@interface OOShaderProgram: NSObject
{
GLhandleARB program;
GLhandleARB vertexShader;
GLhandleARB fragmentShader;
NSString *key;
}

View File

@ -120,11 +120,13 @@ static NSString *GetGLSLInfoLog(GLhandleARB shaderObject);
{
OO_ENTER_OPENGL();
#ifndef NDEBUG
if (EXPECT_NOT(sActiveProgram == self))
{
OOLog(@"shader.dealloc.imbalance", @"***** OOShaderProgram deallocated while active, indicating a retain/release imbalance. Expect imminent crash.");
[OOShaderProgram applyNone];
}
#endif
if (key != nil)
{
@ -133,8 +135,6 @@ static NSString *GetGLSLInfoLog(GLhandleARB shaderObject);
}
glDeleteObjectARB(program);
glDeleteObjectARB(vertexShader);
glDeleteObjectARB(fragmentShader);
[super dealloc];
}
@ -185,6 +185,8 @@ static NSString *GetGLSLInfoLog(GLhandleARB shaderObject);
BOOL OK = YES;
const GLcharARB *sourceString = NULL;
GLint compileStatus;
GLhandleARB vertexShader;
GLhandleARB fragmentShader;
OO_ENTER_OPENGL();
@ -258,11 +260,12 @@ static NSString *GetGLSLInfoLog(GLhandleARB shaderObject);
key = [inKey copy];
}
if (vertexShader != NULL) glDeleteObjectARB(vertexShader);
if (fragmentShader != NULL) glDeleteObjectARB(fragmentShader);
if (!OK)
{
if (vertexShader) glDeleteObjectARB(vertexShader);
if (fragmentShader) glDeleteObjectARB(fragmentShader);
if (program) glDeleteObjectARB(program);
if (program != NULL) glDeleteObjectARB(program);
[self release];
self = nil;

View File

@ -187,7 +187,7 @@ static unsigned sCacheMisses = 0;
NSEnumerator *substEnum = nil;
NSMutableString *mutable = nil;
mutable = [string mutableCopy];
mutable = [[string mutableCopy] autorelease];
if (mutable == nil) return nil;
for (substEnum = [_substitutions keyEnumerator]; (subst = [substEnum nextObject]); )

View File

@ -43,10 +43,12 @@ BOOL CheckOpenGLErrors(NSString *format, ...)
// Short-circut here, because glGetError() is quite expensive.
if (OOLogWillDisplayMessagesInClass(kOOLogOpenGLError))
{
errCode = glGetError();
if (errCode != GL_NO_ERROR)
for (;;)
{
errCode = glGetError();
if (errCode == GL_NO_ERROR) break;
errorOccurred = YES;
errString = gluErrorString(errCode);
if (format == nil) format = @"<unknown>";

View File

@ -41,7 +41,7 @@ MA 02110-1301, USA.
*/
#if defined(LINUX) || defined(OOLITE_SDL_MAC)
#if OOLITE_SDL
#import "SDLSound.h"
#import "SDLMusic.h"
#import "OOBasicSoundSource.h"

View File

@ -0,0 +1,83 @@
/*
OOSoundSourcePool.h
Manages a fixed number of sound sources and distributes sounds between them.
Each sound has a priority and an expiry time. When a new sound is played, it
replaces (if possible) a sound of lower priority that has expired, a sound of
the same priority that has expired, or a sound of lower priority that has not
expired.
All sounds are specified by customsounds.plist key.
Oolite
Copyright (C) 2004-2008 Giles C Williams and contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
This file may also be distributed under the MIT/X11 license:
Copyright (C) 2008 Jens Ayton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#import <Foundation/Foundation.h>
#import "OOTypes.h"
@interface OOSoundSourcePool: NSObject
{
struct OOSoundSourcePoolElement *_sources;
uint8_t _count;
uint8_t _latest;
OOTimeDelta _minRepeat;
OOTimeAbsolute _nextRepeat;
NSString *_lastKey;
}
+ (id) poolWithCount:(uint8_t)count minRepeatTime:(OOTimeDelta)minRepeat;
- (id) initWithCount:(uint8_t)count minRepeatTime:(OOTimeDelta)minRepeat;
- (void) playSoundWithKey:(NSString *)key
priority:(float)priority
expiryTime:(OOTimeDelta)expiryTime;
- (void) playSoundWithKey:(NSString *)key
priority:(float)priority; // expiryTime:0.1 +/- 0.5
- (void) playSoundWithKey:(NSString *)key; // priority: 1.0, expiryTime:0.1 +/- 0.5
@end

View File

@ -0,0 +1,221 @@
/*
OOSoundSourcePool.m
Oolite
Copyright (C) 2004-2008 Giles C Williams and contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
This file may also be distributed under the MIT/X11 license:
Copyright (C) 2008 Jens Ayton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#import "OOSoundSourcePool.h"
#import "OOSound.h"
#import "Universe.h"
enum
{
kNoSlot = UINT8_MAX
};
typedef struct OOSoundSourcePoolElement
{
OOSoundSource *source;
OOTimeAbsolute expiryTime;
float priority;
} PoolElement;
@interface OOSoundSourcePool (Private)
- (uint8_t) selectSlotForPriority:(float)priority;
@end
@implementation OOSoundSourcePool
+ (id) poolWithCount:(uint8_t)count minRepeatTime:(OOTimeDelta)minRepeat
{
return [[[self alloc] initWithCount:count minRepeatTime:minRepeat] autorelease];
}
- (id) initWithCount:(uint8_t)count minRepeatTime:(OOTimeDelta)minRepeat
{
if ((self = [super init]))
{
// Sanity-check count
if (count == 0) count = 1;
if (count == kNoSlot) --count;
_count = count;
if (minRepeat < 0.0) minRepeat = 0.0;
_minRepeat = minRepeat;
// Create source pool
_sources = calloc(sizeof(PoolElement), count);
if (_sources == NULL)
{
[self release];
self = nil;
}
}
return self;
}
- (void) dealloc
{
uint8_t i;
for (i = 0; i != _count; i++)
{
[_sources[i].source release];
}
[_lastKey release];
[super dealloc];
}
- (void) playSoundWithKey:(NSString *)key
priority:(float)priority
expiryTime:(OOTimeDelta)expiryTime
{
uint8_t slot;
OOTimeAbsolute now, absExpiryTime;
PoolElement *element = NULL;
OOSound *sound = NULL;
// Convert expiry time to absolute
now = [UNIVERSE getTime];
absExpiryTime = expiryTime + now;
// Avoid repeats if required
if (now < _nextRepeat && [key isEqualToString:_lastKey]) return;
// Look for a slot in the source list to use
slot = [self selectSlotForPriority:priority];
if (slot == kNoSlot) return;
element = &_sources[slot];
// Load sound
sound = [OOSound soundWithCustomSoundKey:key];
if (sound == nil) return;
// Stop playing sound or set up sound source as appropriate
if (element->source != nil) [element->source stop];
else
{
element->source = [[OOSoundSource alloc] init];
if (element->source == nil) return;
}
// Play and store metadata
[element->source playSound:sound];
element->expiryTime = absExpiryTime;
element->priority = priority;
if (_minRepeat > 0.0)
{
_nextRepeat = now + _minRepeat;
[_lastKey release];
_lastKey = [key copy];
}
// Set staring search location for next slot lookup
_latest = slot;
}
- (void) playSoundWithKey:(NSString *)key
priority:(float)priority
{
[self playSoundWithKey:key
priority:priority
expiryTime:0.5 + randf() * 0.1];
}
- (void) playSoundWithKey:(NSString *)key
{
[self playSoundWithKey:key priority:1.0];
}
@end
@implementation OOSoundSourcePool (Private)
- (uint8_t) selectSlotForPriority:(float)priority
{
uint8_t curr, count, expiredLower = kNoSlot, unexpiredLower = kNoSlot, expiredEqual = kNoSlot;
PoolElement *element = NULL;
OOTimeAbsolute now = [UNIVERSE getTime];
#define NEXT(x) (((x) + 1) % _count)
curr = _latest;
count = _count;
do
{
curr = NEXT(curr);
element = &_sources[curr];
if (element->source == nil || ![element->source isPlaying]) return curr; // Best type of slot: empty
else if (element->priority < priority)
{
if (element->expiryTime <= now) expiredLower = curr; // Second-best type: expired lower-priority
else unexpiredLower = curr; // Third-best type: unexpired lower-priority
}
else if (element->priority == priority && element->expiryTime <= now)
{
expiredEqual = curr; // Fourth-best type: expired equal-priority.
}
} while (--count);
if (expiredLower != kNoSlot) return expiredLower;
if (unexpiredLower != kNoSlot) return unexpiredLower;
return expiredEqual; // Will be kNoSlot if none found
}
@end

View File

@ -518,7 +518,7 @@ static NSMutableDictionary *string_cache;
NSEnumerator *enumerator = nil;
NSString *path = nil;
NSString *arrayPath = nil;
NSMutableArray *array = nil;
NSMutableArray *array = nil;
NSArray *arrayNonEditable = nil;
if (fileName == nil) return nil;
@ -551,8 +551,7 @@ static NSMutableDictionary *string_cache;
for (enumerator = [ResourceManager pathEnumerator]; (path = [enumerator nextObject]); )
{
arrayPath = [path stringByAppendingPathComponent:fileName];
[array release];
array = [OOArrayFromFile(arrayPath) mutableCopy];
array = [[OOArrayFromFile(arrayPath) mutableCopy] autorelease];
if (array != nil) [results addObject:array];
// Special handling for arrays merging. Currently, equipment.plist only gets its objects merged.
@ -566,8 +565,7 @@ static NSMutableDictionary *string_cache;
if (folderName != nil)
{
arrayPath = [[path stringByAppendingPathComponent:folderName] stringByAppendingPathComponent:fileName];
[array release];
array = [OOArrayFromFile(arrayPath) mutableCopy];
array = [[OOArrayFromFile(arrayPath) mutableCopy] autorelease];
if (array != nil) [results addObject:array];
if (array != nil && [[array objectAtIndex:0] isKindOfClass:[NSArray class]])

View File

@ -29,7 +29,7 @@ MA 02110-1301, USA.
@interface OOJSScript: OOScript <OOWeakReferenceSupport>
{
JSObject *object;
JSObject *_jsSelf;
NSString *name;
NSString *description;

View File

@ -130,18 +130,18 @@ static JSFunctionSpec sScriptMethods[] =
if (!problem)
{
// Do we actually want parent to be the global object here?
object = JS_NewObject(context, &sScriptClass, sScriptPrototype, NULL /*JS_GetGlobalObject(context)*/);
if (object == NULL) problem = @"allocation failure";
_jsSelf = JS_NewObject(context, &sScriptClass, sScriptPrototype, NULL /*JS_GetGlobalObject(context)*/);
if (_jsSelf == NULL) problem = @"allocation failure";
}
if (!problem)
{
if (!JS_SetPrivate(context, object, [self weakRetain])) problem = @"could not set private backreference";
if (!JS_SetPrivate(context, _jsSelf, [self weakRetain])) problem = @"could not set private backreference";
}
if (!problem)
{
if (![engine addGCRoot:&object named:"Script object"])
if (![engine addGCRoot:&_jsSelf named:"Script object"])
{
problem = @"could not add JavaScript root object";
}
@ -149,7 +149,7 @@ static JSFunctionSpec sScriptMethods[] =
if (!problem)
{
script = LoadScriptWithName(context, path, object, &problem);
script = LoadScriptWithName(context, path, _jsSelf, &problem);
}
// Set properties.
@ -168,7 +168,7 @@ static JSFunctionSpec sScriptMethods[] =
// Run the script (allowing it to set up the properties we need, as well as setting up those event handlers)
if (!problem)
{
if (!JS_ExecuteScript(context, object, script, &returnValue))
if (!JS_ExecuteScript(context, _jsSelf, script, &returnValue))
{
problem = @"could not run script";
}
@ -211,9 +211,13 @@ static JSFunctionSpec sScriptMethods[] =
[name release];
[description release];
[version release];
[weakSelf weakRefDrop];
[[OOJavaScriptEngine sharedEngine] removeGCRoot:&object];
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
JSObjectWrapperFinalize(context, _jsSelf); // Release weakref to self
JS_RemoveRoot(context, &_jsSelf); // Unroot jsSelf
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
[weakSelf weakRefDrop];
[super dealloc];
}
@ -290,7 +294,7 @@ static JSFunctionSpec sScriptMethods[] =
jsval value;
JSFunction *function = NULL;
OK = JS_GetProperty(context, object, [eventName UTF8String], &value);
OK = JS_GetProperty(context, _jsSelf, [eventName UTF8String], &value);
#if SUPPORT_CHANGED_HANDLERS
if (!OK || value == JSVAL_VOID)
@ -317,7 +321,7 @@ static JSFunctionSpec sScriptMethods[] =
{
for (oldNameEnum = [oldNames objectEnumerator]; (oldName = [oldNameEnum nextObject]) && value == JSVAL_VOID && OK; )
{
OK = JS_GetProperty(context, object, [oldName UTF8String], &value);
OK = JS_GetProperty(context, _jsSelf, [oldName UTF8String], &value);
if (OK && value != JSVAL_VOID)
{
@ -380,7 +384,7 @@ static JSFunctionSpec sScriptMethods[] =
}
// Actually call the function
OK = JS_CallFunction(context, object, function, argc, argv, &value);
OK = JS_CallFunction(context, _jsSelf, function, argc, argv, &value);
// Re-garbage-collectibalize the arguments and free the array
if (argv != NULL)
@ -424,7 +428,7 @@ static JSFunctionSpec sScriptMethods[] =
if (propName == nil) return nil;
context = [[OOJavaScriptEngine sharedEngine] acquireContext];
OK = JSGetNSProperty(NULL, object, propName, &value);
OK = JSGetNSProperty(NULL, _jsSelf, propName, &value);
if (OK && !JSVAL_IS_VOID(value)) result = JSValueToObject(context, value);
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
@ -444,7 +448,7 @@ static JSFunctionSpec sScriptMethods[] =
jsValue = [value javaScriptValueInContext:context];
if (!JSVAL_IS_VOID(jsValue))
{
result = JSDefineNSProperty(context, object, propName, jsValue, NULL, NULL, JSPROP_ENUMERATE);
result = JSDefineNSProperty(context, _jsSelf, propName, jsValue, NULL, NULL, JSPROP_ENUMERATE);
}
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
return result;
@ -463,7 +467,7 @@ static JSFunctionSpec sScriptMethods[] =
jsValue = [value javaScriptValueInContext:context];
if (!JSVAL_IS_VOID(jsValue))
{
result = JSDefineNSProperty(context, object, propName, jsValue, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
result = JSDefineNSProperty(context, _jsSelf, propName, jsValue, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
}
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
return result;
@ -472,7 +476,7 @@ static JSFunctionSpec sScriptMethods[] =
- (jsval)javaScriptValueInContext:(JSContext *)context
{
return OBJECT_TO_JSVAL(object);
return OBJECT_TO_JSVAL(_jsSelf);
}

View File

@ -31,6 +31,7 @@ MA 02110-1301, USA.
#import "OOColor.h"
#import "OOWeakReference.h"
#import "OOTypes.h"
#import "OOSound.h"
@class GameController, CollisionRegion, MyOpenGLView, GuiDisplayGen,
Entity, ShipEntity, StationEntity, PlanetEntity, PlayerEntity,
@ -121,7 +122,7 @@ enum
#define BILLBOARD_DEPTH 50000.0
@interface Universe: NSObject <OOWeakReferenceSupport>
@interface Universe: OOWeakRefObject
{
@public
// use a sorted list for drawing and other activities
@ -243,8 +244,6 @@ enum
NSMutableArray *entitiesDeadThisUpdate;
OOWeakReference *weakSelf;
#if OOLITE_MAC_OS_X
NSSpeechSynthesizer *speechSynthesizer; // use this from OS X 10.3 onwards
NSArray *speechArray;
@ -409,7 +408,8 @@ enum
- (void) setViewDirection:(OOViewID) vd;
- (OOViewID) viewDirection;
- (BOOL) playCustomSound:(NSString*)key;
- (BOOL) playCustomSound:(NSString*)key; // DEPRECATED -- use +[OOSound soundWithCustomSoundKey:] and OOSoundSource.
- (NSString *) soundNameForCustomSoundKey:(NSString *)key;
- (void) clearPreviousMessage;
- (void) setMessageGuiBackgroundColor:(OOColor *) some_color;
@ -575,3 +575,21 @@ OOINLINE Universe *GetUniverse(void)
#define DESC(key) ([UNIVERSE descriptionForKey:(key "")]) // Only for use with string literals, and only for looking up strings.
@interface OOSound (OOCustomSounds)
+ (id) soundWithCustomSoundKey:(NSString *)key;
- (id) initWithCustomSoundKey:(NSString *)key;
@end
@interface OOSoundSource (OOCustomSounds)
+ (id) sourceWithCustomSoundKey:(NSString *)key;
- (id) initWithCustomSoundKey:(NSString *)key;
- (void) playCustomSoundWithKey:(NSString *)key;
@end

View File

@ -320,8 +320,6 @@ static NSComparisonResult comparePrice(NSDictionary *dict1, NSDictionary *dict2,
[[OOCacheManager sharedCache] flush];
[weakSelf weakRefDrop];
#ifndef OOLITE_MAC_OS_X
[speechArray release];
[speechSynthesizer release];
@ -331,19 +329,6 @@ static NSComparisonResult comparePrice(NSDictionary *dict1, NSDictionary *dict2,
}
- (id)weakRetain
{
if (weakSelf == nil) weakSelf = [OOWeakReference weakRefWithObject:self];
return [weakSelf retain];
}
- (void)weakRefDied:(OOWeakReference *)weakRef
{
if (weakRef == weakSelf) weakSelf = nil;
}
#ifdef ALLOW_PROCEDURAL_PLANETS
- (BOOL) doProcedurallyTexturedPlanets
{
@ -4920,20 +4905,19 @@ OOINLINE BOOL EntityInRange(Vector p1, Entity *e2, float range)
}
- (NSString *) soundNameForCustomSoundKey:(NSString *)key;
{
return [customsounds stringForKey:key];
}
- (BOOL) playCustomSound:(NSString*)key
{
NSString *fileName = nil;
fileName = [customsounds stringForKey:key];
if (fileName != nil)
OOSound* sound = [OOSound soundWithCustomSoundKey:key];
if (sound)
{
OOSound* sound = [ResourceManager ooSoundNamed:fileName inFolder:@"Sounds"];
if (sound)
{
if (![sound isPlaying])
[sound play];
return YES;
}
[sound play];
return YES;
}
return NO;
}
@ -7955,3 +7939,55 @@ static NSComparisonResult comparePrice(NSDictionary *dict1, NSDictionary *dict2,
}
@end
@implementation OOSound (OOCustomSounds)
+ (id) soundWithCustomSoundKey:(NSString *)key
{
NSString *fileName = [UNIVERSE soundNameForCustomSoundKey:key];
if (fileName == nil) return nil;
return [ResourceManager ooSoundNamed:fileName inFolder:@"Sounds"];
}
- (id) initWithCustomSoundKey:(NSString *)key
{
[self release];
return [[[self class] soundWithCustomSoundKey:key] retain];
}
@end
@implementation OOSoundSource (OOCustomSounds)
+ (id) sourceWithCustomSoundKey:(NSString *)key
{
return [[[self alloc] initWithCustomSoundKey:key] autorelease];
}
- (id) initWithCustomSoundKey:(NSString *)key
{
OOSound *theSound = [OOSound soundWithCustomSoundKey:key];
if (theSound != nil)
{
self = [self initWithSound:theSound];
}
else
{
[self release];
self = nil;
}
return self;
}
- (void) playCustomSoundWithKey:(NSString *)key
{
OOSound *theSound = [OOSound soundWithCustomSoundKey:key];
if (theSound != nil) [self playSound:theSound];
}
@end