top of page

Salary Theft Simulator

A critical VR simulation game where rest becomes a risk and productivity produces harm. (Personal Project)

Salary Theft Simulator - A critical VR simulation game where rest becomes a risk and productivity produces harm. Built with Unity + XR Interaction Toolkit, featuring: VR interaction system Boss surveillance AI Stealth mechanics Immersive, humorous office environment Explores interaction design, game feel, and VR player experience.


Link to Github:

https://github.com/Swaiky666/SalaryTheftRepo



🌌 Background


Salary Theft Simulator presents a workplace where labor directly produces psychological pressure.The player assumes the role of an employee whose stress level increases whenever they work.If stress exceeds a critical threshold, the employee suffers a health breakdown.

At the same time, the employee must complete a minimum amount of daily work to avoid termination.This creates a constant conflict between survival within the system and self-preservation.

The game frames stress not as a personal weakness, but as a structural outcome of contemporary labor conditions Rest, distraction, and idleness become necessary counter-actions rather than moral failures.


⚙️ Core Gameplay Mechanics


  • Stress Accumulation System: Performing work tasks or just staying at office increases the player’s stress level. Excessive stress leads to illness or failure states.


  • Mandatory Productivity Quota: Each day requires a minimum amount of completed work to prevent being fired, enforcing constant pressure.


  • Stress Relief Through “Unproductive” Actions: Activities such as eating, using a phone, or resting reduce stress but do not contribute to productivity.


  • Surveillance and Avoidance: Company leaders and cameras monitor the workplace.Stress-relief actions must be performed discreetly to avoid penalties.


  • Risk Management Loop: Gameplay centers on balancing productivity, stress, and visibility under surveillance rather than optimizing efficiency.


🔁 Game Flow




VR interactive buttons

Game Tutorial

Print document

Submit documents

Cleaning

There is various kinds of program-generated trash in the office area, such as crumpled paper and spilled coffee.

Sneaking food

Sneaking food can reduce stress, and some foods even have buffs, such as a temporary increase in movement speed.

Play mobile games

Control your mobile game character by holding and shaking your phone.



Monitor

A white light indicates no player is within range, yellow indicates a player is present, and red indicates the current player is slacking off.

Was caught slacking off(Monitor)

Was caught slacking off(Boss)



Pressure value ui

NPC patrol system


Workspace UI Information

Daily task board



⚙️Technical Showcase


1. NPC Behavior Tree Architecture

Clean, extensible AI with composable nodes(csharp)
public class NPCBehaviorTree
{
    private void BuildBehaviorTree()
    {
        rootNode = new SelectorNode(
            // Priority 1: Avoid obstacles
            new SequenceNode(
                new ConditionNode(() => npc.HasObstacleAhead),
                new ActionNode(AvoidObstacle)
            ),
            // Priority 2: Special points
            new SequenceNode(
                new ConditionNode(() => npc.EnableSpecialPoints),
                new ActionNode(CheckForSpecialPoints)
            ),
            // Priority 3: Path following
            new ActionNode(FollowPath)
        );
    }
}

2. Advanced Vision System


NPCs track players with realistic head rotation and line-of-sight(csharp)

private void ScanForPlayer() {     Vector3 detectionDirection = GetHeadLookDirection(); // Head follows rotation          foreach (Collider collider in Physics.OverlapSphere(transform.position, _playerDetectionDistance))     {         if (collider.CompareTag(_playerTag))         {             // Check angle and raycast for occlusion             RaycastHit hit;             if (Physics.Raycast(eyePosition, rayDirection, out hit, distance))             {                 if (hit.collider.CompareTag(_playerTag))                 {                     _hasPlayerInSight = true;                     LockOntoPlayer(collider.transform);                 }                 else if (IsBlockingObject(hit.collider))                 {                     _isPlayerBlocked = true; // Player hidden                 }             }         }     } }

3. Dynamic Special Points System

NPCs interrupt patrols to visit points of interest with probability-based activation(csharp)
public Transform GetNearbySpecialPoint()
{
    foreach (Transform specialPoint in _specialPoints)
    {
        float distance = Vector3.Distance(transform.position, specialPoint.position);
        if (distance <= _specialPointDetectionRange)
        {
            // Cooldown prevents spam
            _specialPointCooldownRemaining = _specialPointCooldownTime;
            
            // Chance roll for natural behavior
            if (Random.Range(0f, 1f) <= _specialPointActivationChance)
            {
                return specialPoint;
            }
        }
    }
    return null;
}

4. VR "Phone Shake" Mini-Game: Technical

Eliminates dependency on absolute world orientation by computing rotations relative to player's starting pose:

Calibrated Relative Rotation System(csharp)
// PhoneShakeDetector.cs
public void Calibrate()
{
    neutralRotation = transform.rotation; // Store "neutral" as reference
    smoothedTiltInput = 0f;
}

private void Update()
{
    // Compute rotation in neutral coordinate space
    Quaternion delta = Quaternion.Inverse(neutralRotation) * transform.rotation;
    
    // Extract roll angle (screen-normal rotation)
    float roll = delta.eulerAngles.z;
    if (roll > 180f) roll -= 360f; // Convert [0,360) to (-180,180]
    
    currentRollAngle = roll;
}

Math insight:

  • Quaternion inverse gives the "opposite" rotation

  • Composition Inverse(neutral) * current yields the delta rotation

  • This is the same principle used in IMU sensors for drift correction


VR Interaction Hook via XR Toolkit(csharp)
// VRGameStarter.cs
private void Start()
{
    interactable = GetComponent<XRBaseInteractable>();
    interactable.selectEntered.AddListener(OnGrabStart);
    interactable.selectExited.AddListener(OnGrabEnd);
}

private void OnGrabStart(SelectEnterEventArgs args)
{
    isBeingGrabbed = true;
    climbingGameUI.StartGame();
}

private void OnGrabEnd(SelectExitEventArgs args)
{
    isBeingGrabbed = false;
    climbingGameUI.StopGame();
}

No button presses required—the act of picking up the phone is the start button. This follows affordance theory from Don Norman's Design of Everyday Things: the phone's graspability naturally suggests its function.



🚀 Future Plans


  1. Add more work-related items and idle / distraction items.

  2. Develop multiplayer gameplay, introducing a new party-style competitive mode where one player takes the role of the manager, and multiple players act as employees.

  3. Implement an in-game shop system where players can spend their earned salary to buy special items, such as

    • specific foods that provide temporary buff effects,

    • special equipment that increases movement speed,

    • or tools that help stay hidden and avoid detection.


🎬 Videos recorded by test players earlier



https://youtu.be/Zq7fKjUAU1E


Project Gallery

bottom of page