Reconnection

D&D-Inspired Turn-Based Combat Meets Stunning Visuals

Project Overview

Reconnection is a D&D-inspired turn-based fighting game built in Unreal Engine, combining tactical combat with beautiful visuals and dynamic narrative choices. As Lead Programmer, I architected the entire combat system in C++, implementing dice-roll mechanics, stat-based calculations, and AI decision-making that brings tabletop RPG combat to life.

Technical Highlights

D&D Combat System

Automated dice rolls, attack/defense calculations, and turn management

Turn-Based Mechanics

Initiative-based turn order with strategic action choices

Enemy AI System

Blueprint-extensible AI behavior for dynamic opponents

C++ Architecture

Clean, extensible parent classes with virtual functions

Buff System

Dynamic stat modifications for strategic depth

Dialogue Choices

Player-driven narrative with branching conversations

Code Showcase

Blueprint Integration & Designer Tools

The C++ AFighter and UEnemy classes are designed for Blueprint extensibility, allowing designers to create unique enemy behaviors, player abilities, and combat encounters without touching code. Key Blueprint-implementable functions include:

🤖 Enemy AI Behaviors

  • ChooseAction() - Implement custom AI decision trees
  • Conditional logic - Enemy evaluates player health, buffs, and position
  • Action selection - Choose between Attack, Heal, Block, or special abilities
  • Difficulty scaling - Adjust AI aggression and strategy per encounter

⚔️ Combat Actions

  • Attack() - Custom attack animations and VFX triggers
  • Heal() - Healing effects with particle systems
  • Block() - Defensive stance animations
  • Die() - Death sequences, loot drops, victory conditions

🎯 Event Delegates

  • OnStartTurn - Trigger UI updates, camera effects
  • OnEndTurn - Queue next fighter in initiative order
  • OnHitAttack - Play hit reactions, damage numbers
  • OnHitMiss - Miss animations, combat feedback

💬 Dialogue Integration

  • Dynamic choices - Player dialogue affects combat stats
  • Narrative branching - Choices influence enemy behavior
  • Combat triggers - Dialogue can start/end encounters
  • Character relationships - Track player decisions for story outcomes

AFighter Class - Combat System Foundation

The AFighter parent class implements all core combat mechanics including turn management, dice-roll calculations (d20 system), damage/healing, and buff systems. Designed with Blueprint integration for designer flexibility while maintaining C++ performance.

AFighter. h - Header Definition

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "AFighter.generated.h"

UCLASS()
class RECONNECTION_API AFighter : public AActor
{
    GENERATED_BODY()
    
public:	
    // Sets default values for this actor's properties
    AFighter();

    //Boolean to check if it's this fighter's turn
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stored Variables")
    bool bIsTurn;

    //Initiative score for turn order
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stored Variables")
    int32 InitiativeScore;

    //Function to start this fighter's turn
    UFUNCTION(BlueprintCallable, Category="Stored Functions")
    void StartTurn();

    //Function to end this fighter's turn	
    UFUNCTION(BlueprintCallable, Category="Stored Functions")
    void EndTurn();

    UFUNCTION(BlueprintCallable, Category = "Stored Functions")
    void SendDamage(float Damage, const FString& Type, AFighter *Target);

    UFUNCTION(BlueprintCallable, Category = "Stored Functions")
    virtual void ReceiveDamage(float Damage, const FString& Type);

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

};
                        

Turn Management & Combat Flow

Implements initiative-based turn order system with clear turn start/end demarcation. The turn management system allows for complex action queuing and supports both player and AI-controlled fighters.

AFighter.cpp - Turn System Implementation

// Fill out your copyright notice in the Description page of Project Settings. 

#include "AFighter.h"

void AFighter::BeginPlay()
{
    Super::BeginPlay();
}

// Sets default values
AFighter::AFighter()
{
    // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. 
    PrimaryActorTick. bCanEverTick = false;

    bIsTurn = false;
    InitiativeScore = 0;
}

void AFighter::StartTurn()
{
    bIsTurn = true;
    UE_LOG(LogTemp, Warning, TEXT("Turn started"));
}

void AFighter::EndTurn()
{
    bIsTurn = false;
    UE_LOG(LogTemp, Warning, TEXT("Turn ended"));
}

void AFighter:: SendDamage(float Damage, const FString& Type, AFighter *Target)
{
    UE_LOG(LogTemp, Warning, TEXT("Sending %f %s damage to target"), Damage, *Type);
}

void AFighter::ReceiveDamage(float Damage, const FString& Type)
{
    UE_LOG(LogTemp, Warning, TEXT("Received %f %s damage from source"), Damage, *Type);
}
                        

D&D-Style Dice Roll System

From the original UFighter implementation: Authentic d20 attack rolls with modifiers, defense calculations, and random damage ranges. This creates unpredictable, strategic combat that feels like tabletop D&D.

UFighter.cpp - Attack & Defense Mechanics

// D20 Attack Roll System
int UFighter::RollToHit()
{
    int Roll = FMath::RandRange(1, 20);  // d20 roll
    return Roll + BaseAttack + AttackBuff;
}

float UFighter::GetDefense()
{
    return BaseDefense + DefenseBuff;
}

void UFighter:: Attack(UFighter *Target)
{
    // Roll to hit vs target defense (classic D&D mechanic)
    if (RollToHit() >= Target->GetDefense())
    {
        SendDamage(RollDamage(), Target);
        OnHitAttack. Broadcast(Target);
    }
    else
    {
        OnHitMiss.Broadcast(Target);
    }
    EndTurn();
}

float UFighter::RollDamage()
{
    // Random damage range with buffs
    float Damage = FMath::RandRange(MinDamage, MaxDamage) + DamageBuff;
    return Damage;
}

void UFighter:: ReceiveDamage_Implementation(float Damage)
{
    // Apply damage with reduction/armor
    CurrentHealth = FMath::Clamp(CurrentHealth - (Damage - DamageReduction), 0.0f, MaxHealth);
    if (CurrentHealth <= 0)
    {
        Die();
        UE_LOG(LogTemp, Warning, TEXT("Fighter has been defeated"));
    }
}
                        

Strategic Action System

Multiple combat actions beyond basic attacks: healing, blocking, and buff management. Each action has strategic tradeoffs, encouraging thoughtful decision-making during combat.

UFighter.cpp - Heal, Block, & Buff Systems

// Healing Action
void UFighter::Heal_Implementation()
{
    CurrentHealth = FMath::Clamp(CurrentHealth + BaseHeal, 0.0f, MaxHealth);
    EndTurn();
}

// Blocking/Defensive Action
void UFighter::Block_Implementation()
{
    DamageReduction = BaseBlock + BlockBuff;
    EndTurn();
}

// Dynamic Buff System
void UFighter::AddBuff(float BuffAmount, const FString& stat)
{
    if (stat == "Attack")
    {
        AttackBuff += BuffAmount;
    }
    else if (stat == "Damage")
    {
        DamageBuff += BuffAmount;
    }
    else if (stat == "Defense")
    {
        DefenseBuff += BuffAmount;
    }
    else if (stat == "Block")
    {
        BlockBuff += BuffAmount;
    }
    else if (stat == "Heal")
    {
        HealBuff += BuffAmount;
    }
}

void UFighter:: RemoveBuff(float BuffAmount, const FString& stat)
{
    if (stat == "Attack")
        AttackBuff -= BuffAmount;
    else if (stat == "Damage")
        DamageBuff -= BuffAmount;
    else if (stat == "Defense")
        DefenseBuff -= BuffAmount;
    else if (stat == "Block")
        BlockBuff -= BuffAmount;
    else if (stat == "Heal")
        HealBuff -= BuffAmount;
}
                        

Enemy AI Architecture

Blueprint-extensible AI system that inherits from UFighter. Designers can implement custom AI behaviors in Blueprints while the C++ foundation handles combat mechanics. This separation of concerns enables rapid iteration.

UEnemy.cpp - AI Decision Making

#include "UEnemy.h"

void UEnemy::StartTurn()
{
    Super::StartTurn();
    
    // Automatically trigger AI decision when turn starts
    ChooseAction();
}

// Blueprint-implementable function for AI logic
void UEnemy::ChooseAction_Implementation()
{
    // Non-blueprint implementation does nothing
    // Designers implement this in Blueprint to define enemy behavior: 
    // - Analyze player health, buffs, position
    // - Choose between Attack, Heal, Block, Special abilities
    // - Execute chosen action
}
                        

Comprehensive Stat System

Tracks 15+ combat statistics including initiative, health, damage ranges, attack bonuses, defense values, and buff modifiers. Provides a complete stat query system for UI and game logic.

UFighter.cpp - Stat Management

TArray<float> UFighter::GetAllStats()
{
    TArray<float> Stats;
    Stats.Add(InitiativeScore);
    Stats.Add(MaxHealth);
    Stats.Add(CurrentHealth);
    Stats.Add(MinDamage);
    Stats.Add(MaxDamage);
    Stats.Add(DamageBuff);
    Stats.Add(BaseAttack);
    Stats.Add(AttackBuff);
    Stats.Add(BaseDefense);
    Stats.Add(DefenseBuff);
    Stats.Add(BaseBlock);
    Stats.Add(BlockBuff);
    Stats.Add(BaseHeal);
    Stats.Add(HealBuff);
    Stats.Add(DamageReduction);
    return Stats;
}

// Example stat usage in combat
void UFighter::SendDamage_Implementation(float Damage, UFighter* Target)
{
    Target->ReceiveDamage(Damage);
}

void UFighter::Die_Implementation()
{
    // Handle death logic here in Blueprint
    // Can trigger animations, VFX, game over states, etc.
}
                        

Team Credits

🎬
Jadyn Englett Producer & Level Design
🖌️
Waldemar Morales Character Art, UI Art, Art Lead
🎮
Wesley Yates Front-End Blueprints, Level Design, and Tech Lead
🎨
Olin Britt-Tores Character Art & 3D Environment
📖
Matthew Polfer Narrative & Level Design
📷
David Diaz Camera & Post-Processing
Daniel Roa VFX & Animations

Developer Reflection

Building Reconnection taught me the importance of designing C++ systems that empower designers. By creating a robust combat foundation with Blueprint extensibility, our team could iterate rapidly on enemy behaviors and game balance while maintaining performant, clean code. Translating the unpredictability and strategy of tabletop D&D into automated combat was an incredibly rewarding challenge!