Dhruv.Contact
Back home

Suspicious

Abstract

A Roblox social-deduction party game for 8–12 players. Secret agents run odd missions (stand under trees, walk backwards, dodge CCTV) while civilians try to spot who's acting off. Wrong accusations help the agents; right ones take them out. Side activities, emergency meetings, cosmetics, and progression — Lua synced via Rojo.

Highlights

  • 8–12 player social deduction with agent missions and civilian investigations
  • Emergency meetings, cosmetics, progression, and side activities
  • Full Roblox Studio + Rojo toolchain — works on install for local testing
LuaRobloxRojoGame DevelopmentSocial Deduction

Suspicious

ok so this among us type game called sus or smth idk, a social deduction party game for roblox. 8–12 players spawn into a detailed city. a few of you are secret agents with weird missions (stand under trees, walk backwards, ring bells, dodge cctv). everyone else is a civilian trying to spot who's acting off. wrong accusations help the agents. right ones take them out. there's side activities so everyone looks busy, emergency meetings, cosmetics, progression, the whole thing. if you know what to do to make this more interesting and stuff, we can do that, and feel free to change anything, add anything, or let me know what needs to be changed code wise to make stuff work if it doesnt. it should work on installation and import into roblox studio, but lmk if you need help.

this readme is your install + test guide. you'll also see a quick intro panel when you first join in-game. test mode is on by default (solo lobbies work). set TestMode = false in GameConfig.lua before you ship.


Quick Start

Prerequisites

  1. Roblox Studio (latest version)
  2. Rojo 7.x — syncs this codebase into Studio
  3. Aftman (optional, for tool management)

Installation

# Clone the repository
git clone <your-repo-url> suspicious
cd suspicious

# Install Rojo (via Aftman)
aftman install

# Start Rojo sync server
rojo serve

# Open Roblox Studio → Rojo plugin → Connect to localhost:34872

Once connected, all scripts and map modules sync into your place automatically.

First Test

  1. Open Studio with Rojo connected
  2. Press Play (F5) — you need 8+ players for a full round, or temporarily lower MinPlayers in GameConfig.lua for solo testing
  3. Watch the Output window for [Suspicious] Server initialized

Gameplay Flow

Lobby (wait for 8–12 players)
  ↓ countdown
Starting (10s grace period, roles assigned)
  ↓
Active (8 min round — missions, accusations, events)
  ↕ emergency meetings (max 2/round)
Results → Intermission → Lobby

Roles

RoleObjectiveSpecial
AgentComplete all secret missions before timer expiresKnows other Agents; gets 3–5 randomized missions
CivilianIdentify and eliminate all Agents2 accusation tokens per round; can call emergency meetings

Agent Count by Lobby Size

PlayersAgents
8–91
10–112
123

Win Conditions

  • Agents win if all living Agents complete their missions, OR timer expires with Agents alive
  • Civilians win if all Agents are eliminated (accusations or meeting votes)

Project Architecture

src/
├── ReplicatedStorage/
│   ├── Packages/          # Promise, Signal (internal utilities)
│   └── Shared/
│       ├── Config/        # All tunable game balance (EDIT THESE)
│       ├── Constants.lua  # Enums, tags, remote names
│       ├── Types.lua      # Luau type definitions
│       ├── Util/          # RandomUtil, TableUtil, PlayerUtil
│       ├── Network/       # RemoteRegistry
│       └── Map/           # MapModule registration
│
├── ServerScriptService/
│   └── Server/
│       ├── init.server.lua    # Server boot
│       ├── MapLoader.server.lua
│       ├── ServiceLoader.lua  # Dependency injection
│       └── Services/          # All server-authoritative logic
│           ├── GameService.lua       # Round orchestrator
│           ├── RoleService.lua       # Agent/Civilian assignment
│           ├── MissionService.lua    # Secret mission tracking
│           ├── AccusationService.lua # Accusation tokens & rewards
│           ├── MeetingService.lua    # Emergency meetings & voting
│           ├── SideActivityService.lua
│           ├── WorldEventService.lua
│           ├── SecurityService.lua   # CCTV, guards, suspicion
│           ├── MapService.lua        # District boundary tracking
│           ├── ProgressionService.lua
│           ├── DataService.lua       # DataStore persistence
│           └── MonetizationService.lua
│
├── StarterPlayer/
│   └── StarterPlayerScripts/
│       └── Client/
│           ├── init.client.lua
│           └── Controllers/
│               ├── UIController.lua
│               ├── MissionController.lua
│               ├── InputController.lua
│               └── ProgressionController.lua
│
├── StarterGui/UI/         # Designer-editable UI assets
├── Workspace/
│   ├── Map/Modules/       # Modular map pieces (designer-built)
│   └── GameSystems/       # Meeting table, CCTV, security room
└── ServerStorage/Assets/  # Server-only assets

Design Principles

  • Server authority — all gameplay logic runs on the server; clients display state only
  • Config separated from code — balance changes go in Shared/Config/ without touching services
  • Modular services — each system is a self-contained ModuleScript registered via ServiceLoader
  • CollectionService tags — map interactables use tags, not hardcoded part names
  • No gameplay monetization — all Robux purchases are cosmetic-only

Extension Points

Adding a New Mission

Edit src/ReplicatedStorage/Shared/Config/MissionConfig.lua:

{
    Id = "my_new_mission",
    Name = "Mission Display Name",
    Description = "What the Agent must do.",
    Category = Constants.MissionCategory.Movement, -- Movement, Interaction, Social, Environmental, Timed
    Difficulty = 2,       -- 1 (easy) to 5 (hard)
    Weight = 8,           -- Higher = more likely to be picked
    Duration = 30,        -- Optional: seconds required
    TargetTag = "Tree",   -- Optional: CollectionService tag
    TargetDistrict = "Park", -- Optional: district name
    RequiredAction = "StayNear", -- Action type (see MissionService)
    Target = 1,           -- Optional: count required (default 1)
},

If the mission needs new tracking logic, add a handler in MissionService:StartTracking().

Adding a Side Activity

Edit src/ReplicatedStorage/Shared/Config/SideActivityConfig.lua and tag an interactable part in Studio with Interactable + SideActivityId attribute.

Adding a World Event

Edit src/ReplicatedStorage/Shared/Config/EventConfig.lua. Implement effect application in WorldEventService:_applyEffects().

Adding Cosmetics

Edit src/ReplicatedStorage/Shared/Config/CosmeticConfig.lua. Set real AssetId values from the Roblox catalog.

Adding Map Districts

See Designer Setup Guide below.

Adding NPCs

  1. Place NPC models under Workspace/Map/Modules/<Module>/NPCs/
  2. Tag with NPCGuard for patrolling guards
  3. Guards automatically increase suspicion for running players nearby

Controls

KeyAction
EInteract with nearest tagged object
MCall emergency meeting

Progression Systems

  • Experience & Levels — earn XP from wins, missions, accusations, side activities
  • Coins — soft currency for cosmetic purchases
  • Achievements — milestone rewards (config in ProgressionConfig.lua)
  • Daily/Weekly Challenges — rotating objectives with coin/XP rewards
  • Seasonal Battle Pass — tier-based cosmetic unlocks (no gameplay advantage)
  • Titles & Trophies — unlockable profile decorations
  • Statistics — wins, accusations, distance, MVP awards, favorite mission type

Monetization (Cosmetic Only)

Configured in CosmeticConfig.lua:

  • Hats, hairstyles, jackets, backpacks
  • Emotes, idle animations, victory poses
  • Trails, spawn effects, profile banners
  • Trophy room decorations
  • Gamepasses: VIP Pass (extra emote slot, lobby badge), Starter Bundle
  • No item provides gameplay advantage

Set GamepassId and AssetId values in Studio after creating gamepasses/catalog items.


Designer Setup Guide (For Non-Programmers)

This section is written for artists and level designers who will never touch code.

Opening the Project

  1. Install Roblox Studio from create.roblox.com
  2. Ask a programmer to run rojo serve and connect Studio via the Rojo plugin
  3. The entire game appears in Studio automatically — you edit visually

Editing the Map

The map is built from modular pieces in Workspace → Map → Modules. Each module is a self-contained district chunk.

Creating a New Map Module

  1. In Studio, go to Workspace → Map → Modules
  2. Duplicate an existing module (e.g., PlazaModule) or create a new Model
  3. Set these Attributes on the Model (Properties panel → Attributes):
    • DistrictName — e.g., "Cafe", "Museum", "Market"
    • ModuleId — unique ID, e.g., "cafe_01"
  4. Add these child folders (create empty Folders):
    • DistrictZone — a large invisible Part defining the district boundary
    • Landmarks, Trees, Benches, Bells, Fountains, Interactables, SpawnPoints
  5. Place your 3D assets inside the appropriate folders
  6. Move/rotate the module to position it in the world

Tagging (Automatic)

When the game starts, MapLoader automatically tags parts based on their parent folder:

  • Parts in Trees/ → tagged Tree
  • Parts in Benches/ → tagged Bench
  • Parts in Landmarks/ → tagged Landmark
  • Parts in Interactables/ → tagged Interactable

You do not need to add tags manually if you use the correct folder names.

Making Something Interactable

  1. Place the part in the Interactables folder
  2. Add an Attribute called SideActivityId with value like "vending_snack" (ask programmer for valid IDs)
  3. Players press E near it to interact

District Zones

The DistrictZone part must be:

  • A Part (not a MeshPart)
  • Large enough to cover the entire district
  • Set to Anchored, CanCollide = false, Transparency = 0.9 (invisible in-game)

Replacing Visual Assets

  1. Find the part or model in the Explorer panel
  2. Change its Color, Material, or replace with your own Mesh/Model
  3. Keep the part in the same folder so tags still work
  4. Do not rename folders like Trees or Landmarks

Adding CCTV Cameras

  1. Go to Workspace → GameSystems → CCTVCameras
  2. Duplicate an existing camera Part
  3. Position it where you want surveillance coverage
  4. Cameras within 30 studs of an Agent increase suspicion

Testing Locally

  1. Press F5 (Play) in Studio
  2. To test alone, ask a programmer to temporarily set MinPlayers = 1 in GameConfig
  3. Check the Output window for errors (View → Output)
  4. Press Shift+F5 to stop

Publishing Updates

  1. File → Publish to Roblox
  2. Add a version note describing your changes
  3. Click Publish
  4. Test on the live game before announcing to players

What NOT to Edit

Do NOT touchWhy
ServerScriptService/Server/Game logic — breaks exploits protection
StarterPlayerScripts/Client/Client code
ReplicatedStorage/Shared/Config/Balance numbers — ask programmer
Script files inside modelsAuto-generated

What You CAN Edit

Safe to editExamples
Workspace/Map/Modules/Buildings, props, terrain
Workspace/GameSystems/Meeting table, cameras (visuals only)
StarterGui/UI/Menu layouts, colors, images
ServerStorage/Assets/3D models, textures
Part colors, materials, meshesAny visual property

Performance Notes

  • Mission tracking runs at 0.5s intervals (not every frame)
  • Suspicion decays over time to prevent permanent penalties
  • DataStore auto-saves every 5 minutes + on player leave
  • CollectionService tags are cached — avoid retagging at runtime

Live Service Checklist

Before publishing:

  • Set real AssetId and GamepassId values in CosmeticConfig.lua
  • Enable Studio API Services (Game Settings → Security → Enable Studio Access to API Services)
  • Configure DataStore in Game Settings
  • Set MinPlayers back to 8 for production
  • Build out all 12 districts with proper DistrictZones
  • Add NPC guard patrol paths
  • Create game thumbnail and description
  • Test with 8+ players in a private server

License

All rights reserved. This codebase is provided for the Suspicious Roblox game project.

Connect with Dhruv Hegde

More of Dhruv Hegde's open-source work on GitHub and LinkedIn.

More projects

← Project gallery