SudoLang Text-based RPG Tutorial: Cyberpunk Edition

Lem Canady
3 min readApr 17, 2023

--

Learn how to create a tiny yet engaging text-based RPG set in a world similar to Shadowrun using SudoLang. This tutorial will guide you through setting up the game world, character creation, a simple combat system, and a quest system with rewards. Let’s get started!

Photo by Sandro Katalina on Unsplash

Setting Up the Game World

First, let’s create a few locations and a way to navigate between them. We will define three areas: City Center, Slums, and Corporate District. Each site has a name and a description. The getLocation function returns a location object based on its name, while the travel function allows a player to move between locations.

locations = [
{ name: "City Center", description: "The bustling heart of the city." },
{ name: "Slums", description: "A dangerous and poverty-stricken area." },
{ name: "Corporate District", description: "Skyscrapers and powerful corporations." }
]

function getLocation(name) => locations |> find(location => location.name == name);

function travel(player, destination) {
player.location = getLocation(destination);
log("You have arrived at $destination.");
}

Character Creation

A simple character creation system will let players choose their character’s name and class. We will define three attributes: Strength, Agility, and Intelligence. Then, we’ll create three types: Street Samurai, Decker, and Rigger. Each class has a primary attribute that affects gameplay. The createCharacter function initializes a new character with the chosen name, type, and starting location.

attributes = ["Strength", "Agility", "Intelligence"]

classes = [
{ name: "Street Samurai", mainAttribute: "Strength" },
{ name: "Decker", mainAttribute: "Intelligence" },
{ name: "Rigger", mainAttribute: "Agility" }
]

function createCharacter(name, class) => {
name,
class,
location: getLocation("City Center"),
health: 100,
mainAttribute: classes |> find(c => c.name == class).mainAttribute,
baseAttributeValue: 10
}

Simple Combat System

The combat system will feature enemies, damage calculations, and random encounters. The calculateDamage function computes the damage dealt by an attacker to a defender based on their attributes. The attack function applies this damage, reducing the defender’s health. The randomEncounter function selects a random enemy for the player to face and initiates combat.

function calculateDamage(attacker, defender) => attacker.baseAttributeValue - defender.baseAttributeValue / 2;

function attack(attacker, defender) {
damage = calculateDamage(attacker, defender);
defender.health -= damage;
log("$attacker.name dealt $damage damage to $defender.name.");
}

function randomEncounter(player) {
enemies = [
{ name: "Ganger", health: 50, baseAttributeValue: 6 },
{ name: "Drone", health: 40, baseAttributeValue: 8 }
];

encounterEnemy = enemies |> sample;
log("You encountered a $encounterEnemy.name!");
attack(player, encounterEnemy);
}

Quests and Rewards

To keep players engaged, let’s add a simple quest system with rewards for completion. We’ll define a single quest, “Clean Up the Slums,” which takes place in the Slums location and offers monetary compensation upon completion. The completeQuest function checks if the player is in the correct area and awards the reward if the quest is complete.

quests = [
{ title: "Clean Up the Slums", location: "Slums", reward: 500 }
];

function completeQuest(player, questTitle) {
quest = quests |> find(q => q.title == questTitle);
if (player.location.name == quest.location) {
log("Congratulations! You completed the '$questTitle' quest!");
player.money += quest.reward;
} else {
log("You must be in $quest.location to complete this quest.");
}
}

Bringing It All Together

Finally, we’ll create the main game loop where the player can input commands to interact with the game world. The loop will continue if the player’s health is above zero. It will prompt the player for input, allowing them to travel between locations, engage in combat, and complete quests.

function gameLoop(player) {
while (player.health > 0) {
log("You are currently at ${player.location.name}. What would you like to do?");
input = getInput();
if (input == "travel") {
log("Where would you like to travel?");
destination = getInput();
travel(player, destination);
} else if (input == "attack") {
randomEncounter(player);
} else if (input == "complete quest") {
log("Which quest would you like to complete?");
questTitle = getInput();
completeQuest(player, questTitle);
} else {
log("Invalid command. Please try again.");
}
}

log("Game Over! Thanks for playing!");
}

player = createCharacter("PlayerName", "Street Samurai");
gameLoop(player);

Conclusion

With this small codebase, we’ve created a simple yet engaging text-based RPG set in a Shadowrun-like world using SudoLang. By focusing on core gameplay elements and leveraging GPT-4’s ability to infer meaning from SudoLang, we’ve kept the total tokens to a minimum. You can now expand on this foundation to create more complex games, adding new features and mechanics to enhance the player experience. Happy coding!

--

--

Lem Canady

Illustrator, Designer & Web 3 Developer — I’m a creative of many different hats. Currently residing in the absolutely beautiful Pacific Northwest.