Add better support for multi-entity battles
This commit is contained in:
		
							parent
							
								
									906d66a12a
								
							
						
					
					
						commit
						2707c46df1
					
				
							
								
								
									
										116
									
								
								src/Debug.c
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								src/Debug.c
									
									
									
									
									
								
							| @ -30,8 +30,64 @@ void debug_init(MemoryArena *arena, v2 windowSize, Font font) | |||||||
| 	GLOBAL_debug.initialConsoleP = V2(consoleXPos, consoleYPos); | 	GLOBAL_debug.initialConsoleP = V2(consoleXPos, consoleYPos); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void debug_consoleLog(char *string, char *file, int lineNum) | ||||||
|  | { | ||||||
|  | 	i32 maxConsoleStrLen = ARRAY_COUNT(GLOBAL_debug.console[0]); | ||||||
|  | 
 | ||||||
|  | 	i32 strIndex = 0; | ||||||
|  | 	i32 fileStrLen = common_strlen(file); | ||||||
|  | 	for (i32 count = 0; strIndex < maxConsoleStrLen; strIndex++, count++) | ||||||
|  | 	{ | ||||||
|  | 		if (fileStrLen <= count) break; | ||||||
|  | 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex] = file[count]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (strIndex < maxConsoleStrLen) | ||||||
|  | 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex++] = ':'; | ||||||
|  | 
 | ||||||
|  | 	char line[12] = {0}; | ||||||
|  | 	common_itoa(lineNum, line, ARRAY_COUNT(line)); | ||||||
|  | 	i32 lineStrLen = common_strlen(line); | ||||||
|  | 	for (i32 count = 0; strIndex < maxConsoleStrLen; strIndex++, count++) | ||||||
|  | 	{ | ||||||
|  | 		if (lineStrLen <= count) break; | ||||||
|  | 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex] = line[count]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (strIndex < maxConsoleStrLen) | ||||||
|  | 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex++] = ':'; | ||||||
|  | 
 | ||||||
|  | 	i32 stringStrLen = common_strlen(string); | ||||||
|  | 	for (i32 count = 0; strIndex < maxConsoleStrLen; strIndex++, count++) | ||||||
|  | 	{ | ||||||
|  | 		if (stringStrLen <= count) break; | ||||||
|  | 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex] = string[count]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (strIndex >= maxConsoleStrLen) | ||||||
|  | 	{ | ||||||
|  | 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-4] = '.'; | ||||||
|  | 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-3] = '.'; | ||||||
|  | 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-2] = '.'; | ||||||
|  | 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-1] = 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	i32 maxConsoleLines = ARRAY_COUNT(GLOBAL_debug.console); | ||||||
|  | 	GLOBAL_debug.consoleIndex++; | ||||||
|  | 
 | ||||||
|  | 	if (GLOBAL_debug.consoleIndex >= maxConsoleLines) | ||||||
|  | 		GLOBAL_debug.consoleIndex = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void debug_pushString(char *formatString, void *data, char *dataType) | void debug_pushString(char *formatString, void *data, char *dataType) | ||||||
| { | { | ||||||
|  | 	if (GLOBAL_debug.numDebugStrings >= | ||||||
|  | 	    ARRAY_COUNT(GLOBAL_debug.debugStrings)) | ||||||
|  | 	{ | ||||||
|  | 		DEBUG_LOG("Debug string stack is full, DEBUG_PUSH() failed"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (GLOBAL_debug.stringUpdateTimer <= 0) | 	if (GLOBAL_debug.stringUpdateTimer <= 0) | ||||||
| 	{ | 	{ | ||||||
| 		i32 numDebugStrings = GLOBAL_debug.numDebugStrings; | 		i32 numDebugStrings = GLOBAL_debug.numDebugStrings; | ||||||
| @ -79,8 +135,6 @@ void debug_pushString(char *formatString, void *data, char *dataType) | |||||||
| 			ASSERT(INVALID_CODE_PATH); | 			ASSERT(INVALID_CODE_PATH); | ||||||
| 		} | 		} | ||||||
| 		GLOBAL_debug.numDebugStrings++; | 		GLOBAL_debug.numDebugStrings++; | ||||||
| 		ASSERT(GLOBAL_debug.numDebugStrings < |  | ||||||
| 		       ARRAY_COUNT(GLOBAL_debug.debugStrings[0])); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -178,6 +232,8 @@ void debug_drawUi(GameState *state, f32 dt) | |||||||
| 	for (i32 i = 0; i < world->freeEntityIndex; i++) | 	for (i32 i = 0; i < world->freeEntityIndex; i++) | ||||||
| 	{ | 	{ | ||||||
| 		Entity *const entity  = &world->entities[i]; | 		Entity *const entity  = &world->entities[i]; | ||||||
|  | 		if (entity->state == entitystate_dead) continue; | ||||||
|  | 
 | ||||||
| 		/* Render debug markers on entities */ | 		/* Render debug markers on entities */ | ||||||
| 		v4 color          = V4(1, 1, 1, 1); | 		v4 color          = V4(1, 1, 1, 1); | ||||||
| 		char *debugString = NULL; | 		char *debugString = NULL; | ||||||
| @ -242,6 +298,13 @@ void debug_drawUi(GameState *state, f32 dt) | |||||||
| 				         entity->stats->actionTimer, entity->stats->actionRate); | 				         entity->stats->actionTimer, entity->stats->actionRate); | ||||||
| 				renderer_string(&state->renderer, &state->arena, cameraBounds, | 				renderer_string(&state->renderer, &state->arena, cameraBounds, | ||||||
| 				                font, entityTimer, strPos, 0, color); | 				                font, entityTimer, strPos, 0, color); | ||||||
|  | 
 | ||||||
|  | 				strPos.y -= GLOBAL_debug.stringLineGap; | ||||||
|  | 				char entityIdTarget[32]; | ||||||
|  | 				snprintf(entityIdTarget, ARRAY_COUNT(entityIdTarget), | ||||||
|  | 				         "Targetting ID: %d", entity->stats->entityIdToAttack); | ||||||
|  | 				renderer_string(&state->renderer, &state->arena, cameraBounds, | ||||||
|  | 				                font, entityIdTarget, strPos, 0, color); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			strPos.y -= GLOBAL_debug.stringLineGap; | 			strPos.y -= GLOBAL_debug.stringLineGap; | ||||||
| @ -290,52 +353,3 @@ void debug_drawUi(GameState *state, f32 dt) | |||||||
| 	renderConsole(&state->renderer, &state->arena); | 	renderConsole(&state->renderer, &state->arena); | ||||||
| 	debug_clearCallCounter(); | 	debug_clearCallCounter(); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| void debug_consoleLog(char *string, char *file, int lineNum) |  | ||||||
| { |  | ||||||
| 	i32 maxConsoleStrLen = ARRAY_COUNT(GLOBAL_debug.console[0]); |  | ||||||
| 
 |  | ||||||
| 	i32 strIndex = 0; |  | ||||||
| 	i32 fileStrLen = common_strlen(file); |  | ||||||
| 	for (i32 count = 0; strIndex < maxConsoleStrLen; strIndex++, count++) |  | ||||||
| 	{ |  | ||||||
| 		if (fileStrLen <= count) break; |  | ||||||
| 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex] = file[count]; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (strIndex < maxConsoleStrLen) |  | ||||||
| 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex++] = ':'; |  | ||||||
| 
 |  | ||||||
| 	char line[12] = {0}; |  | ||||||
| 	common_itoa(lineNum, line, ARRAY_COUNT(line)); |  | ||||||
| 	i32 lineStrLen = common_strlen(line); |  | ||||||
| 	for (i32 count = 0; strIndex < maxConsoleStrLen; strIndex++, count++) |  | ||||||
| 	{ |  | ||||||
| 		if (lineStrLen <= count) break; |  | ||||||
| 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex] = line[count]; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (strIndex < maxConsoleStrLen) |  | ||||||
| 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex++] = ':'; |  | ||||||
| 
 |  | ||||||
| 	i32 stringStrLen = common_strlen(string); |  | ||||||
| 	for (i32 count = 0; strIndex < maxConsoleStrLen; strIndex++, count++) |  | ||||||
| 	{ |  | ||||||
| 		if (stringStrLen <= count) break; |  | ||||||
| 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex] = string[count]; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (strIndex >= maxConsoleStrLen) |  | ||||||
| 	{ |  | ||||||
| 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-4] = '.'; |  | ||||||
| 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-3] = '.'; |  | ||||||
| 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-2] = '.'; |  | ||||||
| 		GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-1] = 0; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	i32 maxConsoleLines = ARRAY_COUNT(GLOBAL_debug.console); |  | ||||||
| 	GLOBAL_debug.consoleIndex++; |  | ||||||
| 
 |  | ||||||
| 	if (GLOBAL_debug.consoleIndex >= maxConsoleLines) |  | ||||||
| 		GLOBAL_debug.consoleIndex = 0; |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -685,8 +685,20 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, | |||||||
| 			entity->stats->entityIdToAttack = | 			entity->stats->entityIdToAttack = | ||||||
| 			    findBestEntityToAttack(world, *entity); | 			    findBestEntityToAttack(world, *entity); | ||||||
| 			break; | 			break; | ||||||
| 		case entitystate_attack: | 
 | ||||||
|  | 		// TODO(doyle): Corner case- if move out of range and entity has
 | ||||||
|  | 		// switched to idle mode, we reach the attacker entity and they continue
 | ||||||
|  | 		// attacking it since there's no check before attack if entity is idle
 | ||||||
|  | 		// or not (i.e. has moved out of frame last frame).
 | ||||||
| 		case entitystate_dead: | 		case entitystate_dead: | ||||||
|  | 			updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); | ||||||
|  | 			setActiveEntityAnim(entity, animlist_hero_idle); | ||||||
|  | 			entity->stats->actionTimer      = entity->stats->actionRate; | ||||||
|  | 			entity->stats->queuedAttack     = entityattack_invalid; | ||||||
|  | 			entity->stats->entityIdToAttack = ENTITY_NULL_ID; | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		case entitystate_attack: | ||||||
| 		default: | 		default: | ||||||
| #ifdef DENGINE_DEBUG | #ifdef DENGINE_DEBUG | ||||||
| 			ASSERT(INVALID_CODE_PATH); | 			ASSERT(INVALID_CODE_PATH); | ||||||
| @ -696,18 +708,12 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, | |||||||
| 	case entitystate_battle: | 	case entitystate_battle: | ||||||
| 		switch (newState) | 		switch (newState) | ||||||
| 		{ | 		{ | ||||||
| 		case entitystate_idle: |  | ||||||
| 			updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); |  | ||||||
| 			setActiveEntityAnim(entity, animlist_hero_idle); |  | ||||||
| 			entity->stats->actionTimer      = entity->stats->actionRate; |  | ||||||
| 			entity->stats->queuedAttack     = entityattack_invalid; |  | ||||||
| 			entity->stats->entityIdToAttack = ENTITY_NULL_ID; |  | ||||||
| 			break; |  | ||||||
| 		case entitystate_attack: | 		case entitystate_attack: | ||||||
| 			break; | 			break; | ||||||
|  | 		case entitystate_idle: | ||||||
| 		case entitystate_dead: | 		case entitystate_dead: | ||||||
| 			updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); | 			updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); | ||||||
| 			setActiveEntityAnim(entity, animlist_hero_wave); | 			setActiveEntityAnim(entity, animlist_hero_idle); | ||||||
| 			entity->stats->actionTimer      = entity->stats->actionRate; | 			entity->stats->actionTimer      = entity->stats->actionRate; | ||||||
| 			entity->stats->queuedAttack     = entityattack_invalid; | 			entity->stats->queuedAttack     = entityattack_invalid; | ||||||
| 			entity->stats->entityIdToAttack = ENTITY_NULL_ID; | 			entity->stats->entityIdToAttack = ENTITY_NULL_ID; | ||||||
| @ -726,9 +732,6 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, | |||||||
| 			entity->stats->busyDuration = 0; | 			entity->stats->busyDuration = 0; | ||||||
| 			setActiveEntityAnim(entity, animlist_hero_battlePose); | 			setActiveEntityAnim(entity, animlist_hero_battlePose); | ||||||
| 			break; | 			break; | ||||||
| 		case entitystate_idle: |  | ||||||
| 			return; |  | ||||||
| 
 |  | ||||||
| 		case entitystate_dead: | 		case entitystate_dead: | ||||||
| 			// TODO(doyle): Repeated logic with battle -> dead
 | 			// TODO(doyle): Repeated logic with battle -> dead
 | ||||||
| 			updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); | 			updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); | ||||||
| @ -737,6 +740,16 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, | |||||||
| 			entity->stats->queuedAttack     = entityattack_invalid; | 			entity->stats->queuedAttack     = entityattack_invalid; | ||||||
| 			entity->stats->entityIdToAttack = ENTITY_NULL_ID; | 			entity->stats->entityIdToAttack = ENTITY_NULL_ID; | ||||||
| 			break; | 			break; | ||||||
|  | 
 | ||||||
|  | 		// NOTE(doyle): Entity has been forced out of an attack (out of range)
 | ||||||
|  | 		case entitystate_idle: | ||||||
|  | 			updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); | ||||||
|  | 			setActiveEntityAnim(entity, animlist_hero_idle); | ||||||
|  | 			entity->stats->busyDuration     = 0; | ||||||
|  | 			entity->stats->actionTimer      = entity->stats->actionRate; | ||||||
|  | 			entity->stats->queuedAttack     = entityattack_invalid; | ||||||
|  | 			entity->stats->entityIdToAttack = ENTITY_NULL_ID; | ||||||
|  | 			break; | ||||||
| 		default: | 		default: | ||||||
| #ifdef DENGINE_DEBUG | #ifdef DENGINE_DEBUG | ||||||
| 			ASSERT(INVALID_CODE_PATH); | 			ASSERT(INVALID_CODE_PATH); | ||||||
| @ -820,19 +833,61 @@ INTERNAL void endAttack(World *world, Entity *attacker) | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Compute attack damage */ | 	/* Compute attack damage */ | ||||||
| 	// TODO(doyle): Use attacker stats in battle equations
 | 	Entity *defender = NULL; | ||||||
| 	Entity *defender = &world->entities[attacker->stats->entityIdToAttack]; |  | ||||||
| 	if (attacker->type == entitytype_hero) |  | ||||||
| 		defender->stats->health -= 50; |  | ||||||
| 	else |  | ||||||
| 		defender->stats->health--; |  | ||||||
| 
 | 
 | ||||||
| 	if (defender->stats->health <= 0) | 	// TODO(doyle): Implement faster lookup for entity id in entity table
 | ||||||
|  | 	do | ||||||
| 	{ | 	{ | ||||||
|  | 		/* Get target entity to attack */ | ||||||
|  | 		for (i32 i = 0; i < world->maxEntities; i++) | ||||||
|  | 		{ | ||||||
|  | 			i32 entityIdToAttack = attacker->stats->entityIdToAttack; | ||||||
|  | 			if (world->entities[i].id == entityIdToAttack) | ||||||
|  | 			{ | ||||||
|  | 				defender = &world->entities[i]; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* If no longer exists, find next best */ | ||||||
|  | 		if (!defender) | ||||||
|  | 		{ | ||||||
|  | 			if (world->numEntitiesInBattle > 1) | ||||||
|  | 			{ | ||||||
|  | 				attacker->stats->entityIdToAttack = | ||||||
|  | 				    findBestEntityToAttack(world, *attacker); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
| #ifdef DENGINE_DEBUG | #ifdef DENGINE_DEBUG | ||||||
| 		DEBUG_LOG("Entity has died"); | 				ASSERT(INVALID_CODE_PATH); | ||||||
| #endif | #endif | ||||||
| 		entityStateSwitch(world, defender, entitystate_dead); | 			} | ||||||
|  | 		} | ||||||
|  | 	}	while (!defender); | ||||||
|  | 
 | ||||||
|  | 	// TODO(doyle): Very susceptible to bugs- ensure if defender is dead the
 | ||||||
|  | 	// attacker immediately locates a new target or exits battle mode. But this
 | ||||||
|  | 	// is necessary since it's possible that by the time the hero is ready to
 | ||||||
|  | 	// apply attack damage another person may of killed it (i.e. party member)
 | ||||||
|  | 	if (defender) | ||||||
|  | 	{ | ||||||
|  | 		// TODO(doyle): Use attacker stats in battle equations
 | ||||||
|  | 		if (attacker->type == entitytype_hero) | ||||||
|  | 			defender->stats->health -= 50; | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			//defender->stats->health--;
 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (defender->stats->health <= 0) | ||||||
|  | 		{ | ||||||
|  | #ifdef DENGINE_DEBUG | ||||||
|  | 			DEBUG_LOG("Entity has died"); | ||||||
|  | #endif | ||||||
|  | 			entityStateSwitch(world, defender, entitystate_dead); | ||||||
|  | 			attacker->stats->entityIdToAttack = | ||||||
|  | 			    findBestEntityToAttack(world, *attacker); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Return attacker back to non-attacking state */ | 	/* Return attacker back to non-attacking state */ | ||||||
| @ -878,11 +933,13 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) | |||||||
| 			// TODO(doyle): Accumulate all dead entities and delete at the
 | 			// TODO(doyle): Accumulate all dead entities and delete at the
 | ||||||
| 			// end. Hence resort/organise entity array once, not every time
 | 			// end. Hence resort/organise entity array once, not every time
 | ||||||
| 			// an entity dies
 | 			// an entity dies
 | ||||||
|  | #if 0 | ||||||
| 			i32 entityIndexInArray = i; | 			i32 entityIndexInArray = i; | ||||||
| 			deleteEntity(&state->arena, world, entityIndexInArray); | 			deleteEntity(&state->arena, world, entityIndexInArray); | ||||||
| 
 | 
 | ||||||
| 			// TODO(doyle): DeleteEntity moves elements down 1, so account for i
 | 			// TODO(doyle): DeleteEntity moves elements down 1, so account for i
 | ||||||
| 			i--; | 			i--; | ||||||
|  | #endif | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -102,6 +102,9 @@ inline char *debug_entityattack_string(i32 val) | |||||||
| 
 | 
 | ||||||
| void debug_init(MemoryArena *arena, v2 windowSize, Font font); | void debug_init(MemoryArena *arena, v2 windowSize, Font font); | ||||||
| 
 | 
 | ||||||
|  | #define DEBUG_LOG(string) debug_consoleLog(string, __FILE__, __LINE__); | ||||||
|  | void debug_consoleLog(char *string, char *file, int lineNum); | ||||||
|  | 
 | ||||||
| #define DEBUG_PUSH_STRING(string) debug_pushString(string, NULL, "char") | #define DEBUG_PUSH_STRING(string) debug_pushString(string, NULL, "char") | ||||||
| #define DEBUG_PUSH_VAR(formatString, data, type)                            \ | #define DEBUG_PUSH_VAR(formatString, data, type)                            \ | ||||||
| 	debug_pushString(formatString, CAST(void *)&data, type) | 	debug_pushString(formatString, CAST(void *)&data, type) | ||||||
| @ -109,7 +112,4 @@ void debug_pushString(char *formatString, void *data, char *dataType); | |||||||
| 
 | 
 | ||||||
| void debug_drawUi(GameState *state, f32 dt); | void debug_drawUi(GameState *state, f32 dt); | ||||||
| 
 | 
 | ||||||
| #define DEBUG_LOG(string) debug_consoleLog(string, __FILE__, __LINE__); |  | ||||||
| void debug_consoleLog(char *string, char *file, int lineNum); |  | ||||||
| 
 |  | ||||||
| #endif | #endif | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user