Add entity attack audio cue
This commit is contained in:
		
							parent
							
								
									9ec87fc8be
								
							
						
					
					
						commit
						190822c1f6
					
				| @ -131,7 +131,6 @@ | ||||
|     <ClCompile Include="src\Shader.c" /> | ||||
|     <ClCompile Include="src\WorldTraveller.c" /> | ||||
|     <ClCompile Include="src\Texture.c" /> | ||||
|     <ClCompile Include="src\Tutorial.cpp" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <None Include="data\shaders\default.frag.glsl" /> | ||||
|  | ||||
| @ -15,9 +15,6 @@ | ||||
|     </Filter> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClCompile Include="src\Tutorial.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="src\WorldTraveller.c"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|  | ||||
| @ -80,6 +80,7 @@ const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena, | ||||
| 
 | ||||
| 	i32 error; | ||||
| 	AudioVorbis audio = {0}; | ||||
| 	audio.type = type; | ||||
| 	audio.file = | ||||
| 	    stb_vorbis_open_memory(fileRead.buffer, fileRead.size, &error, NULL); | ||||
| 	 | ||||
| @ -94,6 +95,8 @@ const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena, | ||||
| 	audio.info            = stb_vorbis_get_info(audio.file); | ||||
| 	audio.lengthInSamples = stb_vorbis_stream_length_in_samples(audio.file); | ||||
| 	audio.lengthInSeconds = stb_vorbis_stream_length_in_seconds(audio.file); | ||||
| 	audio.data            = CAST(u8 *) fileRead.buffer; | ||||
| 	audio.size            = fileRead.size; | ||||
| 
 | ||||
| 	assetManager->audio[type] = audio; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										125
									
								
								src/Audio.c
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								src/Audio.c
									
									
									
									
									
								
							| @ -6,6 +6,8 @@ | ||||
| #include "Dengine/Assets.h" | ||||
| #include "Dengine/Audio.h" | ||||
| #include "Dengine/Debug.h" | ||||
| #include "Dengine/MemoryArena.h" | ||||
| #include "dengine/Platform.h" | ||||
| 
 | ||||
| #define AL_CHECK_ERROR() alCheckError_(__FILE__, __LINE__); | ||||
| void alCheckError_(const char *file, int line) | ||||
| @ -101,13 +103,8 @@ const i32 audio_init(AudioManager *audioManager) | ||||
| 		alGenSources(1, &audioManager->sourceList[i].id); | ||||
| 		AL_CHECK_ERROR(); | ||||
| 
 | ||||
| 		// NOTE(doyle): If last entry, loop the free source to front of list
 | ||||
| 		if (i + 1 >= ARRAY_COUNT(audioManager->sourceList)) | ||||
| 			audioManager->sourceList[i].nextFreeIndex = 0; | ||||
| 		else | ||||
| 			audioManager->sourceList[i].nextFreeIndex = i+1; | ||||
| 		audioManager->sourceList[i].isFree = TRUE; | ||||
| 	} | ||||
| 	audioManager->freeSourceIndex = 0; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -119,44 +116,41 @@ INTERNAL inline u32 getSourceId(AudioManager *audioManager, | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| INTERNAL i32 rendererAcquire(AudioManager *audioManager, | ||||
| INTERNAL i32 rendererAcquire(MemoryArena *arena, AudioManager *audioManager, | ||||
|                              AudioRenderer *audioRenderer) | ||||
| { | ||||
| 
 | ||||
| 	i32 vacantSource = audioManager->freeSourceIndex; | ||||
| 
 | ||||
| #ifdef DENGINE_DEBUG | ||||
| 	ASSERT(audioManager && audioRenderer); | ||||
| 	ASSERT(vacantSource >= 0); | ||||
| 	ASSERT(arena && audioManager && audioRenderer); | ||||
| #endif | ||||
| 
 | ||||
| 	if (audioManager->sourceList[vacantSource].nextFreeIndex == | ||||
| 	    AUDIO_NO_FREE_SOURCE) | ||||
| 	{ | ||||
| 		// TODO(doyle): Error messaging return paths
 | ||||
| 		DEBUG_LOG("rendererAcquire(): Failed to acquire free source, all busy"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	u32 checkSource = getSourceId(audioManager, audioRenderer); | ||||
| 	if (alIsSource(checkSource) == AL_TRUE) | ||||
| 	{ | ||||
| 		DEBUG_LOG( | ||||
| 		    "rendererAcquire(): Renderer has not been released before " | ||||
| 		    "acquiring, force release by stopping stream"); | ||||
| 		audio_streamStopVorbis(audioManager, audioRenderer); | ||||
| 		audio_streamStopVorbis(arena, audioManager, audioRenderer); | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO(doyle): Super bad linear O(n) search for every audio-enabled entity
 | ||||
| 	i32 vacantSource = AUDIO_SOURCE_UNASSIGNED; | ||||
| 	for (i32 i = 0; i < ARRAY_COUNT(audioManager->sourceList); i++) | ||||
| 	{ | ||||
| 		if (audioManager->sourceList[i].isFree) | ||||
| 		{ | ||||
| 			vacantSource = i; | ||||
| 			audioManager->sourceList[i].isFree = FALSE; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (vacantSource == AUDIO_SOURCE_UNASSIGNED) | ||||
| 	{ | ||||
| 		DEBUG_LOG("rendererAcquire(): Failed to acquire free source, all busy"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Assign a vacant source slot to renderer */ | ||||
| 	audioRenderer->sourceIndex = vacantSource; | ||||
| 
 | ||||
| 	/* Update the immediate free source index */ | ||||
| 	audioManager->freeSourceIndex = | ||||
| 	    audioManager->sourceList[vacantSource].nextFreeIndex; | ||||
| 
 | ||||
| 	/* Mark current source as in use */ | ||||
| 	audioManager->sourceList[vacantSource].nextFreeIndex = AUDIO_NO_FREE_SOURCE; | ||||
| 
 | ||||
| 	/* Generate audio data buffers */ | ||||
| 	alGenBuffers(ARRAY_COUNT(audioRenderer->bufferId), audioRenderer->bufferId); | ||||
| 	AL_CHECK_ERROR(); | ||||
| @ -166,7 +160,7 @@ INTERNAL i32 rendererAcquire(AudioManager *audioManager, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| INTERNAL const i32 rendererRelease(AudioManager *audioManager, | ||||
| INTERNAL const i32 rendererRelease(MemoryArena *arena, AudioManager *audioManager, | ||||
|                                    AudioRenderer *audioRenderer) | ||||
| { | ||||
| 
 | ||||
| @ -181,8 +175,29 @@ INTERNAL const i32 rendererRelease(AudioManager *audioManager, | ||||
| 		return result; | ||||
| 	} | ||||
| 
 | ||||
| 	alSourceUnqueueBuffers(alSourceId, ARRAY_COUNT(audioRenderer->bufferId), | ||||
| 	/*
 | ||||
| 	  NOTE(doyle): Doing an alSourceRewind will result in the source going to | ||||
| 	  the AL_INITIAL state, but the properties of the source (position, | ||||
| 	  velocity, etc.) will not change. | ||||
| 	*/ | ||||
| 	alSourceRewind(alSourceId); | ||||
| 	AL_CHECK_ERROR(); | ||||
| 
 | ||||
| 	// TODO(doyle): We can possible remove this by just attaching the null buffer ..
 | ||||
| 	ALint numProcessedBuffers; | ||||
| 	alGetSourcei(alSourceId, AL_BUFFERS_PROCESSED, &numProcessedBuffers); | ||||
| 	if (numProcessedBuffers > 0) | ||||
| 	{ | ||||
| 		alSourceUnqueueBuffers(alSourceId, numProcessedBuffers, | ||||
| 		                       audioRenderer->bufferId); | ||||
| 	} | ||||
| 	AL_CHECK_ERROR(); | ||||
| 
 | ||||
| 	// NOTE(doyle): Any buffer queued up that has not been played cannot be
 | ||||
| 	// deleted without being played once. We can set the source buffers to NULL
 | ||||
| 	// (0) to free up the buffer, since we still hold the reference ids for the
 | ||||
| 	// buffer in our audio structure we can delete it afterwards ..
 | ||||
| 	alSourcei(alSourceId, AL_BUFFER, 0); | ||||
| 	alDeleteBuffers(ARRAY_COUNT(audioRenderer->bufferId), | ||||
| 	                audioRenderer->bufferId); | ||||
| 	AL_CHECK_ERROR(); | ||||
| @ -192,21 +207,22 @@ INTERNAL const i32 rendererRelease(AudioManager *audioManager, | ||||
| 		audioRenderer->bufferId[i] = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	stb_vorbis_close(audioRenderer->audio->file); | ||||
| 	PLATFORM_MEM_FREE(arena, audioRenderer->audio, sizeof(AudioVorbis)); | ||||
| 
 | ||||
| 	audioRenderer->audio    = NULL; | ||||
| 	audioRenderer->numPlays = 0; | ||||
| 
 | ||||
| 	u32 sourceIndexToFree      = audioRenderer->sourceIndex; | ||||
| 	audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED; | ||||
| 
 | ||||
| 	audioManager->sourceList[sourceIndexToFree].nextFreeIndex = | ||||
| 	    audioManager->freeSourceIndex; | ||||
| 	audioManager->freeSourceIndex = sourceIndexToFree; | ||||
| 	audioManager->sourceList[sourceIndexToFree].isFree = TRUE; | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| #define AUDIO_CHUNK_SIZE_ 65536 | ||||
| const i32 audio_streamPlayVorbis(AudioManager *audioManager, | ||||
| const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager, | ||||
|                                  AudioRenderer *audioRenderer, | ||||
|                                  AudioVorbis *vorbis, i32 numPlays) | ||||
| { | ||||
| @ -218,7 +234,7 @@ const i32 audio_streamPlayVorbis(AudioManager *audioManager, | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	i32 result = rendererAcquire(audioManager, audioRenderer); | ||||
| 	i32 result = rendererAcquire(arena, audioManager, audioRenderer); | ||||
| 	if (result) | ||||
| 	{ | ||||
| 		DEBUG_LOG("audio_streamPlayVorbis() failed: Could not acquire renderer"); | ||||
| @ -237,13 +253,30 @@ const i32 audio_streamPlayVorbis(AudioManager *audioManager, | ||||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| 	audioRenderer->audio    = vorbis; | ||||
| 	// NOTE(doyle): We make a copy of the audio vorbis file using all the same
 | ||||
| 	// data except the file pointer. If the same sound is playing twice
 | ||||
| 	// simultaneously, we need unique file pointers into the data to track song
 | ||||
| 	// position uniquely
 | ||||
| 	AudioVorbis *copyAudio     = PLATFORM_MEM_ALLOC(arena, 1, AudioVorbis); | ||||
| 	copyAudio->type            = vorbis->type; | ||||
| 	copyAudio->info            = vorbis->info; | ||||
| 	copyAudio->lengthInSamples = vorbis->lengthInSamples; | ||||
| 	copyAudio->lengthInSeconds = vorbis->lengthInSeconds; | ||||
| 
 | ||||
| 	copyAudio->data            = vorbis->data; | ||||
| 	copyAudio->size            = vorbis->size; | ||||
| 
 | ||||
| 	i32 error; | ||||
| 	copyAudio->file = | ||||
| 	    stb_vorbis_open_memory(copyAudio->data, copyAudio->size, &error, NULL); | ||||
| 
 | ||||
| 	audioRenderer->audio    = copyAudio; | ||||
| 	audioRenderer->numPlays = numPlays; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| const i32 audio_streamStopVorbis(AudioManager *audioManager, | ||||
| const i32 audio_streamStopVorbis(MemoryArena *arena, AudioManager *audioManager, | ||||
|                                  AudioRenderer *audioRenderer) | ||||
| { | ||||
| 	i32 result     = 0; | ||||
| @ -252,7 +285,7 @@ const i32 audio_streamStopVorbis(AudioManager *audioManager, | ||||
| 	{ | ||||
| 		alSourceStop(alSourceId); | ||||
| 		AL_CHECK_ERROR(); | ||||
| 		result = rendererRelease(audioManager, audioRenderer); | ||||
| 		result = rendererRelease(arena, audioManager, audioRenderer); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -300,18 +333,20 @@ const i32 audio_streamResumeVorbis(AudioManager *audioManager, | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| const i32 audio_updateAndPlay(AudioManager *audioManager, | ||||
| const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager, | ||||
|                               AudioRenderer *audioRenderer) | ||||
| { | ||||
| 	AudioVorbis *audio = audioRenderer->audio; | ||||
| 	if (!audio) return 0; | ||||
| 
 | ||||
| #if 0 | ||||
| 	if (audioRenderer->numPlays != AUDIO_REPEAT_INFINITE && | ||||
| 	    audioRenderer->numPlays <= 0) | ||||
| 	{ | ||||
| 		i32 result = rendererRelease(audioManager, audioRenderer); | ||||
| 		i32 result = rendererRelease(arena, audioManager, audioRenderer); | ||||
| 		return result; | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	u32 alSourceId = getSourceId(audioManager, audioRenderer); | ||||
| 	if (alIsSource(alSourceId) == AL_FALSE) | ||||
| @ -345,13 +380,12 @@ const i32 audio_updateAndPlay(AudioManager *audioManager, | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				i32 result = rendererRelease(audioManager, audioRenderer); | ||||
| 				i32 result = | ||||
| 				    rendererRelease(arena, audioManager, audioRenderer); | ||||
| 				return result; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// TODO(doyle): Possible bug! Multiple sources playing same file seeking
 | ||||
| 		// file ptr to start may interrupt other stream
 | ||||
| 		stb_vorbis_seek_start(audio->file); | ||||
| 		for (i32 i = 0; i < ARRAY_COUNT(audioRenderer->bufferId); i++) | ||||
| 		{ | ||||
| @ -380,6 +414,7 @@ const i32 audio_updateAndPlay(AudioManager *audioManager, | ||||
| 		AL_CHECK_ERROR(); | ||||
| 		if (numProcessedBuffers > 0) | ||||
| 		{ | ||||
| 			// TODO(doyle): Possibly wrong, we should pass in all processed buffers?
 | ||||
| 			ALint numBuffersToUnqueue = 1; | ||||
| 			ALuint emptyBufferId; | ||||
| 			alSourceUnqueueBuffers(alSourceId, numBuffersToUnqueue, | ||||
|  | ||||
							
								
								
									
										29
									
								
								src/Debug.c
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								src/Debug.c
									
									
									
									
									
								
							| @ -189,6 +189,13 @@ void debug_pushString(char *formatString, void *data, char *dataType) | ||||
| 			         ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), | ||||
| 			         formatString, val.x, val.y); | ||||
| 		} | ||||
| 		else if (common_strcmp(dataType, "v3") == 0) | ||||
| 		{ | ||||
| 			v3 val = *(CAST(v3 *) data); | ||||
| 			snprintf(GLOBAL_debug.debugStrings[numDebugStrings], | ||||
| 			         ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), | ||||
| 			         formatString, val.x, val.y, val.z); | ||||
| 		} | ||||
| 		else if (common_strcmp(dataType, "i32") == 0) | ||||
| 		{ | ||||
| 			i32 val = *(CAST(i32 *) data); | ||||
| @ -394,6 +401,19 @@ void debug_drawUi(GameState *state, f32 dt) | ||||
| 			char *entityStateStr = debug_entitystate_string(entity->state); | ||||
| 			renderer_string(&state->renderer, &state->arena, cameraBounds, font, | ||||
| 			                entityStateStr, strPos, V2(0, 0), 0, color); | ||||
| 
 | ||||
| 			if (entity->audioRenderer) | ||||
| 			{ | ||||
| 				strPos.y -= GLOBAL_debug.stringLineGap; | ||||
| 				char entityAudioSourceIndex[32]; | ||||
| 				snprintf(entityAudioSourceIndex, | ||||
| 				         ARRAY_COUNT(entityAudioSourceIndex), | ||||
| 				         "AudioSource Index: %d", | ||||
| 				         entity->audioRenderer->sourceIndex); | ||||
| 				renderer_string(&state->renderer, &state->arena, cameraBounds, | ||||
| 				                font, entityAudioSourceIndex, strPos, V2(0, 0), | ||||
| 				                0, color); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -418,6 +438,15 @@ void debug_drawUi(GameState *state, f32 dt) | ||||
| 	i32 debug_kbAllocated = state->arena.bytesAllocated / 1024; | ||||
| 	DEBUG_PUSH_VAR("TotalMemoryAllocated: %dkb", debug_kbAllocated, "i32"); | ||||
| 
 | ||||
| 	AudioManager *audioManager = &state->audioManager; | ||||
| 	DEBUG_PUSH_STRING("== Audio System =="); | ||||
| 	for (i32 i = 0; i < ARRAY_COUNT(audioManager->sourceList); i++) | ||||
| 	{ | ||||
| 		v3 tmp = V3i(i, audioManager->sourceList[i].id, | ||||
| 		             audioManager->sourceList[i].isFree); | ||||
| 		DEBUG_PUSH_VAR("Source ID[%02.0f].id[%02.0f].isFree: %1.0f", tmp, "v3"); | ||||
| 	} | ||||
| 
 | ||||
| 	DEBUG_PUSH_STRING("== EntityIDs in Battle List == "); | ||||
| 	DEBUG_PUSH_VAR("NumEntitiesInBattle: %d", world->numEntitiesInBattle, | ||||
| 	               "i32"); | ||||
|  | ||||
							
								
								
									
										10
									
								
								src/Entity.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/Entity.c
									
									
									
									
									
								
							| @ -77,6 +77,9 @@ void entity_addGenericMob(MemoryArena *arena, AssetManager *assetManager, | ||||
| 	b32 collides         = TRUE; | ||||
| 	Entity *mob = entity_add(arena, world, pos, size, type, dir, tex, collides); | ||||
| 
 | ||||
| 	mob->audioRenderer = PLATFORM_MEM_ALLOC(arena, 1, AudioRenderer); | ||||
| 	mob->audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED; | ||||
| 
 | ||||
| 	/* Populate mob animation references */ | ||||
| 	entity_addAnim(assetManager, mob, animlist_hero_idle); | ||||
| 	entity_addAnim(assetManager, mob, animlist_hero_walk); | ||||
| @ -125,7 +128,7 @@ Entity *entity_add(MemoryArena *arena, World *world, v2 pos, v2 size, | ||||
| 		entity.stats               = PLATFORM_MEM_ALLOC(arena, 1, EntityStats); | ||||
| 		entity.stats->maxHealth    = 100; | ||||
| 		entity.stats->health       = entity.stats->maxHealth; | ||||
| 		entity.stats->actionRate   = 100; | ||||
| 		entity.stats->actionRate   = 80; | ||||
| 		entity.stats->actionTimer  = entity.stats->actionRate; | ||||
| 		entity.stats->actionSpdMul = 100; | ||||
| 		entity.stats->entityIdToAttack = -1; | ||||
| @ -147,8 +150,13 @@ Entity *entity_add(MemoryArena *arena, World *world, v2 pos, v2 size, | ||||
| void entity_delete(MemoryArena *arena, World *world, i32 entityIndex) | ||||
| { | ||||
| 	Entity *entity = &world->entities[entityIndex]; | ||||
| 
 | ||||
| 	if (entity->stats) | ||||
| 		PLATFORM_MEM_FREE(arena, entity->stats, sizeof(EntityStats)); | ||||
| 
 | ||||
| 	if (entity->audioRenderer) | ||||
| 		PLATFORM_MEM_FREE(arena, entity->audioRenderer, sizeof(AudioRenderer)); | ||||
| 
 | ||||
| 	// TODO(doyle): Inefficient shuffle down all elements
 | ||||
| 	for (i32 i             = entityIndex; i < world->freeEntityIndex - 1; i++) | ||||
| 		world->entities[i] = world->entities[i + 1]; | ||||
|  | ||||
| @ -187,6 +187,8 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) | ||||
| 	asset_loadVorbis(assetManager, arena, audioPath, audiolist_battle); | ||||
| 	audioPath = "data/audio/Yuki Kajiura - Swordland.ogg"; | ||||
| 	asset_loadVorbis(assetManager, arena, audioPath, audiolist_overworld); | ||||
| 	audioPath = "data/audio/nuindependent_hit22.ogg"; | ||||
| 	asset_loadVorbis(assetManager, arena, audioPath, audiolist_tackle); | ||||
| 
 | ||||
| #ifdef DENGINE_DEBUG | ||||
| 	DEBUG_LOG("Sound assets initialised"); | ||||
| @ -278,6 +280,8 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) | ||||
| 	tex             = asset_getTexture(assetManager, texlist_hero); | ||||
| 	collides        = TRUE; | ||||
| 	Entity *hero = entity_add(arena, world, pos, size, type, dir, tex, collides); | ||||
| 	hero->audioRenderer = PLATFORM_MEM_ALLOC(arena, 1, AudioRenderer); | ||||
| 	hero->audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED; | ||||
| 
 | ||||
| 	/* Populate hero animation references */ | ||||
| 	entity_addAnim(assetManager, hero, animlist_hero_idle); | ||||
| @ -579,7 +583,6 @@ INTERNAL inline void resetEntityState(World *world, Entity *entity) | ||||
| 
 | ||||
| INTERNAL void beginAttack(World *world, Entity *attacker) | ||||
| { | ||||
| 
 | ||||
| #ifdef DENGINE_DEBUG | ||||
| 	ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID); | ||||
| 	ASSERT(attacker->state == entitystate_battle); | ||||
| @ -596,17 +599,18 @@ INTERNAL void beginAttack(World *world, Entity *attacker) | ||||
| 			attacker->dPos.x += (1.0f * METERS_TO_PIXEL); | ||||
| 		else | ||||
| 			attacker->dPos.x -= (1.0f * METERS_TO_PIXEL); | ||||
| 
 | ||||
| 		break; | ||||
| 	default: | ||||
| #ifdef DENGINE_DEBUG | ||||
| 		ASSERT(INVALID_CODE_PATH); | ||||
| #endif | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| INTERNAL void endAttack(World *world, Entity *attacker) | ||||
| INTERNAL void endAttack(MemoryArena *arena, AssetManager *assetManager, | ||||
|                         AudioManager *audioManager, World *world, | ||||
|                         Entity *attacker) | ||||
| { | ||||
| #ifdef DENGINE_DEBUG | ||||
| 	ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID); | ||||
| @ -621,11 +625,18 @@ INTERNAL void endAttack(World *world, Entity *attacker) | ||||
| 		else | ||||
| 			attacker->dPos.x += (1.0f * METERS_TO_PIXEL); | ||||
| 
 | ||||
| #if 1 | ||||
| 		audio_streamPlayVorbis(arena, audioManager, attacker->audioRenderer, | ||||
| 		                       asset_getVorbis(assetManager, audiolist_tackle), | ||||
| 		                       1); | ||||
| #endif | ||||
| 
 | ||||
| 		break; | ||||
| 	default: | ||||
| #ifdef DENGINE_DEBUG | ||||
| 		ASSERT(INVALID_CODE_PATH); | ||||
| #endif | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Compute attack damage */ | ||||
| @ -681,8 +692,9 @@ INTERNAL void endAttack(World *world, Entity *attacker) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| INTERNAL void entityStateSwitch(World *world, Entity *entity, | ||||
|                                 enum EntityState newState) | ||||
| INTERNAL void entityStateSwitch(MemoryArena *arena, AssetManager *assetManager, | ||||
|                                 AudioManager *audioManager, World *world, | ||||
|                                 Entity *entity, enum EntityState newState) | ||||
| { | ||||
| #ifdef DENGINE_DEBUG | ||||
| 	ASSERT(world && entity) | ||||
| @ -718,6 +730,7 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, | ||||
| #ifdef DENGINE_DEBUG | ||||
| 			ASSERT(INVALID_CODE_PATH); | ||||
| #endif | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	case entitystate_battle: | ||||
| @ -736,13 +749,14 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, | ||||
| #ifdef DENGINE_DEBUG | ||||
| 			ASSERT(INVALID_CODE_PATH); | ||||
| #endif | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	case entitystate_attack: | ||||
| 		switch (newState) | ||||
| 		{ | ||||
| 		case entitystate_battle: | ||||
| 			endAttack(world, entity); | ||||
| 			endAttack(arena, assetManager, audioManager, world, entity); | ||||
| 			entity_setActiveAnim(entity, animlist_hero_battlePose); | ||||
| 			entity->stats->actionTimer  = entity->stats->actionRate; | ||||
| 			entity->stats->busyDuration = 0; | ||||
| @ -756,6 +770,7 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, | ||||
| #ifdef DENGINE_DEBUG | ||||
| 			ASSERT(INVALID_CODE_PATH); | ||||
| #endif | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	case entitystate_dead: | ||||
| @ -768,12 +783,14 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, | ||||
| #ifdef DENGINE_DEBUG | ||||
| 			ASSERT(INVALID_CODE_PATH); | ||||
| #endif | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	default: | ||||
| #ifdef DENGINE_DEBUG | ||||
| 		ASSERT(INVALID_CODE_PATH); | ||||
| #endif | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	entity->state = newState; | ||||
| @ -790,6 +807,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) | ||||
| 	Renderer *renderer         = &state->renderer; | ||||
| 	World *const world         = &state->world[state->currWorldIndex]; | ||||
| 	Font *font                 = &assetManager->font; | ||||
| 	MemoryArena *arena         = &state->arena; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 ****************************** | ||||
| @ -798,37 +816,55 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) | ||||
| 	 */ | ||||
| 	Entity *hero               = getHeroEntity(world); | ||||
| 	v4 cameraBounds            = createCameraBounds(world, renderer->size); | ||||
| 	AudioManager *audioManager = &state->audioManager; | ||||
| 	ASSERT(world->freeEntityIndex < world->maxEntities); | ||||
| 	for (i32 i = 0; i < world->freeEntityIndex; i++) | ||||
| 	{ | ||||
| 		Entity *const entity = &world->entities[i]; | ||||
| 
 | ||||
| 		if (entity->audioRenderer) | ||||
| 		if (entity->type == entitytype_soundscape) | ||||
| 		{ | ||||
| 			AudioRenderer *audioRenderer = entity->audioRenderer; | ||||
| 			if (world->numEntitiesInBattle > 0) | ||||
| 			{ | ||||
| 				AudioVorbis *battleTheme = | ||||
| 				    asset_getVorbis(assetManager, audiolist_battle); | ||||
| 				if (audioRenderer->audio != battleTheme) | ||||
| 				if (audioRenderer->audio) | ||||
| 				{ | ||||
| 					audio_streamPlayVorbis(&state->audioManager, audioRenderer, | ||||
| 					                       battleTheme, AUDIO_REPEAT_INFINITE); | ||||
| 					if (audioRenderer->audio->type != audiolist_battle) | ||||
| 					{ | ||||
| 						audio_streamPlayVorbis(arena, &state->audioManager, | ||||
| 						                       audioRenderer, battleTheme, | ||||
| 						                       AUDIO_REPEAT_INFINITE); | ||||
| 					} | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					audio_streamPlayVorbis(arena, &state->audioManager, | ||||
| 					                       audioRenderer, battleTheme, | ||||
| 					                       AUDIO_REPEAT_INFINITE); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				AudioVorbis *overworldTheme = | ||||
| 				    asset_getVorbis(assetManager, audiolist_overworld); | ||||
| 				if (audioRenderer->audio != overworldTheme) | ||||
| 				if (audioRenderer->audio) | ||||
| 				{ | ||||
| 					audio_streamPlayVorbis(&state->audioManager, audioRenderer, | ||||
| 					                       overworldTheme, | ||||
| 					if (audioRenderer->audio->type != audiolist_overworld) | ||||
| 					{ | ||||
| 						audio_streamPlayVorbis(arena, &state->audioManager, | ||||
| 						                       audioRenderer, overworldTheme, | ||||
| 						                       AUDIO_REPEAT_INFINITE); | ||||
| 					} | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					audio_streamPlayVorbis(arena, &state->audioManager, | ||||
| 					                       audioRenderer, overworldTheme, | ||||
| 					                       AUDIO_REPEAT_INFINITE); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			audio_updateAndPlay(&state->audioManager, entity->audioRenderer); | ||||
| 		} | ||||
| 
 | ||||
| 		if (entity->state == entitystate_dead) | ||||
| @ -849,6 +885,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) | ||||
| 			// an entity dies
 | ||||
| #if 1 | ||||
| 			i32 entityIndexInArray = i; | ||||
| 			audio_streamStopVorbis(arena, &state->audioManager, | ||||
| 			                       entity->audioRenderer); | ||||
| 			entity_delete(&state->arena, world, entityIndexInArray); | ||||
| 
 | ||||
| 			// TODO(doyle): DeleteEntity moves elements down 1, so account for i
 | ||||
| @ -888,7 +926,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) | ||||
| 				newState = entitystate_idle; | ||||
| 			} | ||||
| 
 | ||||
| 			entityStateSwitch(world, entity, newState); | ||||
| 			entityStateSwitch(arena, assetManager, audioManager, world, entity, | ||||
| 			                  newState); | ||||
| 		} | ||||
| 
 | ||||
| 		/*
 | ||||
| @ -911,7 +950,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) | ||||
| 						stats->queuedAttack = entityattack_tackle; | ||||
| 
 | ||||
| 					/* Launch up attack animation */ | ||||
| 					entityStateSwitch(world, entity, entitystate_attack); | ||||
| 					entityStateSwitch(arena, assetManager, audioManager, world, | ||||
| 					                  entity, entitystate_attack); | ||||
| 				} | ||||
| 			} | ||||
| 			else if (entity->state == entitystate_attack) | ||||
| @ -922,7 +962,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) | ||||
| 				if (stats->busyDuration <= 0) | ||||
| 				{ | ||||
| 					/* Apply attack damage */ | ||||
| 					entityStateSwitch(world, entity, entitystate_battle); | ||||
| 					entityStateSwitch(arena, assetManager, audioManager, world, | ||||
| 					                  entity, entitystate_battle); | ||||
| 
 | ||||
| 					/* Get target entity that was attacked */ | ||||
| 					Entity *defender = NULL; | ||||
| @ -946,13 +987,21 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) | ||||
| #ifdef DENGINE_DEBUG | ||||
| 						DEBUG_LOG("Entity has died"); | ||||
| #endif | ||||
| 						entityStateSwitch(world, defender, entitystate_dead); | ||||
| 						entityStateSwitch(world, attacker, entitystate_idle); | ||||
| 						entityStateSwitch(arena, assetManager, audioManager, world, defender, | ||||
| 						                  entitystate_dead); | ||||
| 						entityStateSwitch(arena, assetManager, audioManager, world, attacker, | ||||
| 						                  entitystate_idle); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (entity->audioRenderer) | ||||
| 		{ | ||||
| 			audio_updateAndPlay(&state->arena, &state->audioManager, | ||||
| 			                    entity->audioRenderer); | ||||
| 		} | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 ************************************************** | ||||
| 		 * Update animations and render entity | ||||
| @ -973,10 +1022,10 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) | ||||
| 		// NOTE(doyle): If battle entities is 1 then only the hero left
 | ||||
| 		if (hero->state == entitystate_battle && | ||||
| 		    world->numEntitiesInBattle == 1) | ||||
| 			entityStateSwitch(world, hero, entitystate_idle); | ||||
| 			entityStateSwitch(arena, assetManager, audioManager, world, hero, entitystate_idle); | ||||
| 		else if (hero->state != entitystate_attack) | ||||
| 		{ | ||||
| 			entityStateSwitch(world, hero, entitystate_battle); | ||||
| 			entityStateSwitch(arena, assetManager, audioManager, world, hero, entitystate_battle); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
|  | ||||
| @ -62,17 +62,22 @@ enum AudioList | ||||
| { | ||||
| 	audiolist_battle, | ||||
| 	audiolist_overworld, | ||||
| 	audiolist_tackle, | ||||
| 	audiolist_count, | ||||
| 	audiolist_invalid, | ||||
| }; | ||||
| 
 | ||||
| typedef struct AudioVorbis | ||||
| { | ||||
| 	enum AudioList type; | ||||
| 	stb_vorbis *file; | ||||
| 	stb_vorbis_info info; | ||||
| 
 | ||||
| 	u32 lengthInSamples; | ||||
| 	f32 lengthInSeconds; | ||||
| 
 | ||||
| 	u8 *data; | ||||
| 	i32 size; | ||||
| } AudioVorbis; | ||||
| 
 | ||||
| typedef struct TexAtlas | ||||
|  | ||||
| @ -5,20 +5,22 @@ | ||||
| 
 | ||||
| #include "Dengine/Common.h" | ||||
| 
 | ||||
| /* Forward Declaration */ | ||||
| typedef struct MemoryArena MemoryArena; | ||||
| 
 | ||||
| #define AUDIO_NO_FREE_SOURCE -1 | ||||
| typedef struct AudioSourceEntry | ||||
| { | ||||
| 	u32 id; | ||||
| 	i32 nextFreeIndex; | ||||
| 	b32 isFree; | ||||
| } AudioSourceEntry; | ||||
| 
 | ||||
| // TODO(doyle): Incorporate memory arena into managers?
 | ||||
| #define AUDIO_MAX_SOURCES 32 | ||||
| typedef struct AudioManager | ||||
| { | ||||
| 	// NOTE(doyle): Source entries point to the next free index
 | ||||
| 	AudioSourceEntry sourceList[AUDIO_MAX_SOURCES]; | ||||
| 	i32 freeSourceIndex; | ||||
| 
 | ||||
| } AudioManager; | ||||
| 
 | ||||
| 
 | ||||
| @ -36,15 +38,15 @@ typedef struct AudioRenderer | ||||
| 
 | ||||
| 
 | ||||
| const i32 audio_init(AudioManager *audioManager); | ||||
| const i32 audio_streamPlayVorbis(AudioManager *audioManager, | ||||
| const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager, | ||||
|                                  AudioRenderer *audioRenderer, | ||||
|                                  AudioVorbis *vorbis, i32 numPlays); | ||||
| const i32 audio_streamStopVorbis(AudioManager *audioManager, | ||||
| const i32 audio_streamStopVorbis(MemoryArena *arena, AudioManager *audioManager, | ||||
|                                  AudioRenderer *audioRenderer); | ||||
| const i32 audio_streamPauseVorbis(AudioManager *audioManager, | ||||
|                                   AudioRenderer *audioRenderer); | ||||
| const i32 audio_streamResumeVorbis(AudioManager *audioManager, | ||||
|                                    AudioRenderer *audioRenderer); | ||||
| const i32 audio_updateAndPlay(AudioManager *audioManager, | ||||
| const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager, | ||||
|                               AudioRenderer *audioRenderer); | ||||
| #endif | ||||
|  | ||||
| @ -55,6 +55,11 @@ INTERNAL inline v2 V2(const f32 x, const f32 y) | ||||
| 	v2 result = {x, y}; | ||||
| 	return result; | ||||
| } | ||||
| INTERNAL inline v3 V3i(const i32 x, const i32 y, const i32 z) | ||||
| { | ||||
| 	v3 result = {CAST(f32)x, CAST(f32)y, CAST(f32)z}; | ||||
| 	return result; | ||||
| } | ||||
| INTERNAL inline v3 V3(const f32 x, const f32 y, const f32 z) | ||||
| { | ||||
| 	v3 result = {x, y, z}; | ||||
|  | ||||
| @ -15,7 +15,6 @@ typedef struct MemoryArena MemoryArena; | ||||
| #define NUM_KEYS 1024 | ||||
| #define METERS_TO_PIXEL 240 | ||||
| 
 | ||||
| 
 | ||||
| typedef struct World | ||||
| { | ||||
| 	Entity *entities; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user