Discuss Scratch

ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

Johnus Doeus>inventory
box
a mysterious box
box
a mysterious box
box
a mysterious box


here's a peek at combat so far
#expiremental version that uses classes
import pickle
from difflib import SequenceMatcher
import random
#find the item of a list that is closest to a string
def findsimilar(thing, inlist):
    similar = {}
    for item in inlist:
        similar[item] = SequenceMatcher(None, item, thing).ratio()
    return list(reversed(sorted(similar.items(),key=lambda x:x[1])))[0][0]
#frog's dialog
frogdialog = {
   "INITIAL": "ribbit",
   "ribbit": {
       "text": "Ribbit",
       "responses": {
           "A": {
               "text": "What?",
               "newdialog": "croak"
           },
           "B": {
               "text": "Why am I talking to a frog??",
               "newdialog": "shrug"
           }
       }
   },
   "croak": {
       "text": "Crrrroak",
       "responses": {
           "A": {
               "text": "What??",
               "newdialog": "ribbit"
           }
       }
   },
   "shrug": {
       "text": "¯\_(ツ)_/¯",
       "responses": {
           "A": {
               "text": "uh... bye"
           }
       }
   }
}
class Creature:
    def __init__(self, name, dialog, inventory, stats, attackable):
        self.name = name
        self.dialog = dialog
        self.inventory = inventory
        self.stats = stats
        self.attackable = attackable
class Player:
    def __init__(self, name, flags, inventory, stats):
        self.name = name
        self.flags = flags
        self.inventory = inventory
        self.stats = stats
#item class
class Item:
    def __init__(self, name, description, detail):
        self.name = name
        self.description = description
        self.detail = detail
#weapon subclass of item
class Weapon(Item):
    def __init__(self, name, description, detail, atkstr):
        super().__init__(name, description, detail)
        self.atkstr = atkstr
#room class definition
class Room:
    def __init__(self, name, directions, descriptions, items, creatures):
        self.name = name
        self.directions = directions
        self.descriptions = descriptions
        self.items = items
        self.creatures = creatures
F_Ex = Room(
        "Forest Exit",
        {
        "south": "Forest Clearing"
        },
        {
        "normal": "The trail on which you came.",
        "detail": "A dark, thin forest trail. The trail continues south."
        },
        {},
        {}
    )
F_C = Room(
        "Forest Clearing",
        {
        "north": "Forest Exit",
        "down": "Forest Pond"
        },
        {
        "normal": "A rocky clearing in the forest.",
        "detail": "The trail widens out into a clearing. \nThere's a hole in the ground a few feet deep with a small pond in the center of the clearing that you can climb into. \nThere is a door to the south.\n There is a trail to the north."
        },
        {},
        {}
    )
F_P = Room(
        "Forest Pond",
        {
        "up": "Forest Clearing"
        },
        {
        "normal": "A pond in the center of the clearing.",
        "detail": "A frog sits on a lily pad in the pond.\n You can climb back out of the hole."
        },
        {},
        {}
    )
F_En = Room(
        "Forest Entrance",
        {
        "north": "Forest Clearing"
        },
        {
        "normal": "The entrance to the forest.",
        "detail": "A dark, thin forest trail. The forest gradually thins into a plains.\nYou may go north back into the clearing."
        },
        {},
        {}
    )
allrooms = {
    "Forest Exit": F_Ex,
    "Forest Clearing": F_C,
    "Forest Pond": F_P,
    "Forest Entrance": F_En
}
allcommands = ["load", "save", "inspect", "inventory", "help", "instructions", "drop", "grab", "look at", "look", "up", "down", "north", "south", "east", "west"]
#make a box and place it in the start room
box = Item("box", "a mysterious box", "an unmarked cardboard box.")
F_Ex.items["box"] = box
sword = Weapon("sword", "sword", "sword", 10)
F_Ex.items["sword"] = sword
#make a frog and place it in the pond room
frog = Creature("frog", frogdialog, {}, {}, False)
F_P.creatures["frog"] = frog
#training dummy (for combat)
dummystats = {
    "hp": 15,
    "maxhp": 15,
    "armor": 1,
    "deflect": 2, #a one in deflect chance of the damage being decreased by armor
    "atkstr": 2,
    "atkacc": 5, #a one in atkacc chance of hitting
    "canattack": True, #magic dummy,
}
dummy = Creature("training dummy", {}, {"boxa": box, "boxb": box}, dummystats, True)
F_En.creatures["dummy"] = dummy
playerstats = {
    "hp": 20,
    "maxhp": 20,
    "armor": 0,
    "deflect": 1,
    "atkstr": 5,
    "atkacc": 2,
}
name = input("What is your name?\n")
if name:
    player = Player(name, {}, {}, playerstats)
else:
    player = Player("Johnus Doeus", {}, {}, playerstats)
#starting room
place = F_Ex
#allow user to quit
command = ""
while not command == "quit":
    #show the normal description of the room
    print(place.descriptions["normal"])
    #list items in the room
    for item in place.items:
        print("There is a " + place.items[item].name + " here.")
    #list creatures in the room
    for creature in place.creatures:
        print("There is a " + place.creatures[creature].name + " in the room.")
    #get input
    command = input(player.name + ">")
    #allow player to move
    if command in place.directions:
        place = allrooms[place.directions[command]]
    #door
    elif place == allrooms["Forest Clearing"] and command == "south":
        print("The door is locked by a password.")
        if input("What is the password?\n") == "password":
            place.directions["south"] = 'Forest Entrance'
            print("The door shudders open.")
        else:
            print("Incorrect password.")
    #print all command names (add descriptions?)
    elif command == "help":
        for command in allcommands:
            print(command)
    #print instuctions
    elif command == "instructions":
        print("This is just a test level, and there isn't much to just yet.\nYou can type 'help' for a list of commands.\nYou can type 'quit' to quit.\nYou can look around with 'look'\nYou can pick up and drop items with 'grab ___' and 'drop ___'\nYou can open your inventory with 'inventory'\nYou can inspect items you are holding with 'inspect ___'\nYou can look at items you aren't holding with 'look at ___'\nYou can talk to creatures by typing 'talk to ___'\nYou can load and save (EXPIREMENTAL) with 'load' and 'save'")
    #combat
    elif command[0:7] == "attack ":
        playerweapons = {}
        creature = command.replace("attack ", "")
        for ccreature in place.creatures:
            if place.creatures[ccreature].name == creature:
                creature = place.creatures[ccreature]
        if creature.attackable:
            for item in player.inventory:
                if type(player.inventory[item]).__name__ == "Weapon":
                    playerweapons[player.inventory[item].name] = player.inventory[item]
            if playerweapons:
                for weapon in playerweapons:
                    print(weapon + " | attack power: " + str(playerweapons[weapon].atkstr))
                weaponchoice = ""
                while not weaponchoice in playerweapons:
                    weaponchoice = input("Choose a weapon:\n")
                    weapon = playerweapons[weaponchoice]
                    player.stats["atkstr"] = weapon.atkstr
            while not creature.stats["hp"] <= 0 or player.stats["hp"] <= 0:
                atkcommand = input("What do you do?\n")
                if atkcommand == "continue":
                    #player's move
                    if random.randint(1, creature.stats["deflect"]) == 1:
                        if player.stats["atkstr"] - creature.stats["armor"] > 0:
                            creature.stats["hp"] -= player.stats["atkstr"] - creature.stats["armor"]
                        else:
                            print("The " + creature.name + " blocked the attack!")
                    else:
                        creature.stats["hp"] -= player.stats["atkstr"]
                    print(creature.name + ": " + str(creature.stats["hp"]) + "/" + str(creature.stats["maxhp"]))
                    #creature's move
                    if random.randint(1, player.stats["deflect"]) == 1:
                        if creature.stats["atkstr"] - player.stats["deflect"] > 0:
                            player.stats["hp"] -= creature.stats["atkstr"] - player.stats["armor"]
                        else:
                            print("You blocked the attack!")
                    else:
                        player.stats["hp"] -= creature.stats["atkstr"]
                    print(player.name + ": " + str(player.stats["hp"]) + "/" + str(player.stats["maxhp"]))
                elif atkcommand == "end":
                    break
            print("The fight ended!")
            if creature.stats["hp"] <= 0:
                print("The " + creature.name + " faints!")
                for item in creature.inventory:
                    print("The " + creature.name + " drops " + creature.inventory[item].name)
                    place.items[item] = creature.inventory[item]
                place.creatures.pop(ccreature)
    #allow player to look at items they aren't holding
    elif command[0:7] == "look at":
        if command.replace("look at", ""):
            for item in place.items:
                if place.items[item].name == command.replace("look at ", ""):
                    print(place.items[item].description)
        else:
            print("look at what?")
    #deeper descriptions
    elif command == "look":
        print(place.descriptions["detail"])
    #allow player to grab items
    elif command[0:4] == "grab":
        if command.replace("grab", ""):
            #figure out what they're grabbing
            tmpitem = ""
            for item in place.items:
                if place.items[item].name == command.replace("grab ", ""):
                    #python gets upset when I put the code in this loop
                    tmpitem = item
                    break
            if tmpitem:
                print(place.items[tmpitem].name + " grabbed!")
                #copy item into inventory and remove item from room
                player.inventory[tmpitem] = place.items[tmpitem]
                place.items.pop(tmpitem)
                tmpitem = ""
            else:
                print("There is no " + command.replace("grab ", "") + " here.")
        else:
            print("Grab what?")
    #allow player to drop items (does the inverse of "grab")
    elif command[0:4] == "drop":
        if command.replace("drop", ""):
            tmpitem = ""
            for item in player.inventory:
                if player.inventory[item].name == command.replace("drop ", ""):
                    tmpitem = item
                    break
            if tmpitem:
                print(player.inventory[tmpitem].name + " dropped!")
                #copy item into inventory and remove item from room
                place.items[tmpitem] = player.inventory[tmpitem]
                player.inventory.pop(tmpitem)
            else:
                print("You don't have a " + command.replace("drop ", "") + ".")
        else:
            print("Drop what?")
    #show the player's inventory (make this better later)
    elif command == "inventory":
        for item in player.inventory:
            print(player.inventory[item].name)
            print(player.inventory[item].description)
    #show detailed description for items in inventory
    elif command[0:7] == "inspect":
        if command.replace("inspect ", ""):
            for item in player.inventory:
                if player.inventory[item].name == command.replace("inspect ", ""):
                    print(player.inventory[item].detail)
        else:
            print("Inspect what?")
    #allow player to talk to creatures
    elif command[0:7] == "talk to":
        activecreature = ""
        #figure out what creature the player is talking to
        for creature in place.creatures:
            if place.creatures[creature].name == command.replace("talk to ", ""):
                activecreature = place.creatures[creature]
                break
        if activecreature:
            userresp = ""
            #get the initial dialog snippet
            currentdialog = activecreature.dialog[activecreature.dialog["INITIAL"]]
            while not userresp == "goodbye":
                print("The " + activecreature.name + " says '" + currentdialog["text"] + "'")
                #print possible responses
                for response in currentdialog["responses"]:
                    print(response + ": " + currentdialog["responses"][response]["text"])
                userresp = input(">").upper()
                if userresp in currentdialog["responses"]:
                    try:
                        print("You say '" + currentdialog["responses"][userresp]["text"] + "' to the " + activecreature.name)
                        #set the current dialog snippet to the new dialog snippet
                        currentdialog = activecreature.dialog[currentdialog["responses"][userresp]["newdialog"]]
                    except:
                        break
                elif not userresp == "goodbye":
                    #tell user if they didn't type a valid response
                    print("'" + userresp + "' is not a valid response.")
    #save (not updated)
    elif command == "save":
        save = {}
        save["player"] = player
        save["place"] = place.name
        save["rooms"] = {}
        for room in allrooms:
            save["rooms"][room] = allrooms[room]
        with open('savedat2.txt', 'wb') as fh:
            pickle.dump(save, fh)
        print("Saved.")
    #load (not updated)
    elif command == "load":
        savefile = open("savedat2.txt", "rb")
        loadedsave = pickle.load(savefile)
        player = loadedsave["player"]
        for room in loadedsave["rooms"]:
            allrooms[room] = loadedsave["rooms"][room]
        place = allrooms[loadedsave["place"]]
        print(F_C)
        print("Loaded.")
        savefile.close()
    #if the command is valid, but cannot be done in the current room
    elif command in allcommands:
        print("You cannot do that here.")
    #if the command is not valid (and is not "quit"), print a similar command
    elif not command == "quit":
        print("command '" + command + "' not found.")
        print("did you mean: " + findsimilar(command, allcommands))

there's a number of glitches here (for example, trying to attack an enemy that doesn't exist crashes the game), but it does technically “”“work”“”
I hope to add strengths and weaknesses to creatures to add another layer to combat.
tell me if there's anything you want changed





ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
NorthenSuperCoders
Scratcher
100+ posts

PyRPG (Python Text Adventure)

How to create it? Do we need a Server? and In these many codes in many post by @ScratchCatHELLO I'm Confused to use which code? Please Tell me what code is correct?

NorthenSuperCoders
A self-programmer - also writes books, him self.
===================================================
ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

NorthenSuperCoders wrote:

How to create it? Do we need a Server? and In these many codes in many post by @ScratchCatHELLO I'm Confused to use which code? Please Tell me what code is correct?

You don't need a server, you just need python 3 (it's not online or anything).
I should probably edit the first post with the current version I'm working on ;/. It just occured to me that I haven't posted the latest update, so I'll try to do that later today (I haven't been working on this in a while because of school.). The code in the OP is old. The newest actual version is this.





ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
NorthenSuperCoders
Scratcher
100+ posts

PyRPG (Python Text Adventure)

Okay! But which software or application needed?

NorthenSuperCoders
A self-programmer - also writes books, him self.
===================================================
NorthenSuperCoders
Scratcher
100+ posts

PyRPG (Python Text Adventure)

Okay! But which software or application needed?

NorthenSuperCoders
A self-programmer - also writes books, him self.
===================================================
NILL_GAMES10
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

this is cool!
quick question:
Im learning Python from a book and using Visual Studio Code, is Python 3.9.5 just to run python, or is it a text editor?

Last edited by NILL_GAMES10 (June 16, 2021 17:55:11)


I've moved accounts. Go to my new account here.
ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

NILL_GAMES10 wrote:

this is cool!

thanks!

NILL_GAMES10 wrote:

Im learning Python from a book and using Visual Studio Code, is Python 3.9.5 just to run python, or is it a text editor?

can you clarify?
the python command can run scripts from files:
[REDACTED]@pop-os:~$ python3.9 myscript.py
0
1
2
3
4
note: ignore the “python3.9” part, this would be “python” or “python3” for you
or it can be used on its own, as a shell:
[REDACTED]@pop-os:~$ python3.9
Python 3.9.5 (default, May 5 2021, 02:58:34)
[GCC 7.5.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> for i in range(5):
... print(i)
...
0
1
2
3
4
>>>
note: ignore the “python3.9” part, this would be “python” or “python3” for you

so it's sorta both, but I wouldn't use the shell unless you're testing a very short script or a module.






ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

okay so update

I redid the whole thing again
now it has some more stuff (maybe)

now there's actually docstrings
#iteration 3
import os
import random
from difflib import SequenceMatcher
from rich import print as rprint
from rich import align
version = "0.1 (BETA)"
class Room:
    """
    Represents a room.
    Attributes
    ----------
    name : str
        the room name (used in dev mode)
    passive : str
        the description that displays after each turn
    detail : str
        the description that displays when you type "look"
    directions : list
        a list of directions a player in the room can move
    items : dict
        a list of item objects
    ents : dict
        a list of entity objects
    Methods
    -------
    ritem(itemname):
        removes an item by name
    rent(entname):
        removes an entity by name
    str(room):
        converts a room into a string listing attributes
    """
    def __init__(room, name, descriptions, directions, items, ents):
        room.name = name
        room.passive = descriptions[0]
        room.detail = descriptions[1]
        room.directions = directions
        room.items = items
        room.ents = ents
    def __str__(room):
        tmpstr = f"{room.name} "
        for item in room.items:
            tmpstr += f"D There is a {item.name}.\n"
        for ent in room.ents:
            tmpstr += f"D A {ent.name} is standing here.\n"
        return tmpstr
    def ritem(room, itemname):
        room.items.pop(itemname)
    def rent(room, entname):
        room.items.pop(entname)
class Item:
    """
    Represents an item.
    Attributes
    ----------
    name : str
        the item name
    short : str
        short description of the item
    long : str
        detailed description of the item
    stats : dict
        a list of stats
        structure is as follows:
        {
            "dmg": 10, #damage of the item
            "critdmg": 15, #damage of the item when it hits something critically
            "sellprice": 30, #sell value
            "buyprice": 35, #buy value
            "atkeffect": randomdmg #executes a function when you use the item to attack
        }
    weapon : bool
        False -> not a weapon
        True -> a weapon
        defaults to False
    """
    def __init__(item, name, descriptions, stats, weapon=False):
        item.name = name
        item.d = descriptions
        item.short = descriptions[0] #brief
        item.long = descriptions[1] #detail
        item.stats = stats
        item.weapon = weapon
class Ent:
    """
    Represents an entity.
    Attributes
    ----------
    name : str
        the entity name
    inv : dict
        the inventory of the entity. consists of a dict of Item objects
    stats : dict
        the stats of the entity
        structure is as follows:
        {
            "hp": 10, #current health
            "maxhp": 10, #full health
            "dmg": 5, #its damage in combat
            "acc": 2, #entity will hit (1/acc)*100 percent of the time
            "crit": 5, #entity will crit (1/crit)*100 percent of the time
            "critdmg": 7, #damage of a critical hit
        }
    hostilemode : int
        whether an entity will attack unprovoked
        2: the entity will attack when the player enters the room it's in
        1: the entity won't fight unprovoked
        0: the entity won't fight
    """
    def __init__(ent, name, inv, stats, hostilemode=1):
        ent.name = name
        ent.inv = inv
        ent.stats = stats
        ent.hostilemode = hostilemode
    def giveitem(ent, player, itemname):
        player["inv"][itemname] = ent.inv[itemname]
        ent.inv[itemname].pop()
    def damage(ent, amount):
        if ent.stats["hp"] - amount < 0:
            ent.stats["hp"] = 0
        else:
            ent.stats["hp"] -= amount
    def heal(ent, amount):
        if ent.stats["hp"] + amount > ent.stats["maxhp"]:
            ent.stats["hp"] = ent.stats["maxhp"]
        else:
            ent.stats["hp"] += amount
    def attack(ent):
        stats = ent.stats
        hitper = (1/stats["acc"])*100
        critper = (1/stats["crit"])*100
        if bool(random.choices([1, 0], weights=[hitper, 100-hitper])[0]):
            if bool(random.choices([1, 0], weights=[critper, 100-critper])[0]):
                rrprint(f"!![bold red]The {ent.name} critically hit you, doing {stats['critdmg']} damage!")
                return stats["critdmg"]
            else:
                rrprint(f"! [bold]The {ent.name} hit you, doing {stats['dmg']} damage!")
                return stats["dmg"]
        else:
            rrprint(f"  [italic]The {ent.name} missed!")
            return 0
title = """      :::::::::  :::   ::: :::::::::  :::::::::   ::::::::
     :+:    :+: :+:   :+: :+:    :+: :+:    :+: :+:    :+:
    +:+    +:+  +:+ +:+  +:+    +:+ +:+    +:+ +:+
   +#++:++#+    +#++:   +#++:++#:  +#++:++#+  :#:
  +#+           +#+    +#+    +#+ +#+        +#+   +#+#
 #+#           #+#    #+#    #+# #+#        #+#    #+#
###           ###    ###    ### ###         ########       """
#find the item of a list that is closest to a string
def findsimilar(thing, inlist):
    similar = {}
    for item in inlist:
        similar[item] = SequenceMatcher(None, item, thing).ratio()
    return list(reversed(sorted(similar.items(),key=lambda x:x[1])))[0][0]
player = {}
def initplayer(name, startroom):
    global player
    player = {
        "name": name,
        "loc": startroom,
        "hp": 30,
        "maxhp": 30,
        "inventory": {}
    }
def noeffect():
    pass
commands = {
    "help": ["print list of commands and descriptions.", "[b]=HELP=[/]\nPrints a list of command and simple descriptions.\n[b]USAGE[/]\nhelp - print list of commands and descriptions\n    command (opt) - print detailed description of the specified command."],
    "help <command>": ["print detailed explanation of <command>."],
    "quit": ["quit game.", "[b]=QUIT=[/]\nExits the game.\n[b]USAGE[/]\nquit - end game\nq - end game"],
    "look": ["look around at the current room.", "[b]=LOOK=[/]\nPrints a detailed description of the current room.\n[b]USAGE[/]\nlook - see description of current room"],
    "north": ["go north.", "[b]=NORTH=[/]\nMoves the player north.\n[b]USAGE[/]\nnorth - move player north\nn - move player north"],
    "west": ["go west.", "[b]=WEST=[/]\nMoves the player west.\n[b]USAGE[/]\nwest - move player west\nw - move player west"],
    "east": ["go east.", "[b]=EAST=[/]\nMoves the player east.\n[b]USAGE[/]\neast - move player east\ne - move player east"],
    "south": ["go south.", "[b]=WEST=[/]\nMoves the player south.\n[b]USAGE[/]\nwest - move player south\ns - move player south"],
    "grab": ["grab item from room.", "[b]=GRAB=[/]\nGrab an item out of the room and place it in your inventory.\n[b]USAGE[/]\ngrab - grab an item\n    item - name of item to grab."],
    "grab": ["drop item into room.", "[b]=DROP=[/]\nDrop an item from your inventory and place it in the room.\n[b]USAGE[/]\ndrop - drop an item\n    item - name of item to drop."],
    "inventory": ["list items in inventory.", "[b]=INVENTORY=[/]\nPrint a list of items in the player's inventory.\n[b]USAGE[/]\ninventory/i - read inventory"],
    "inspect": ["show detailed description of an item.", "[b]=INSPECT=[/]\nShow a detailed description of an item in your inventory.\n[b]USAGE[/]\ninspect - show long item description"],
    "clear": ["clear cmd prompt/terminal.", "[b]=CLEAR=[/]\nClear screen (for when the terminal has a lot of text in it).\n[b]USAGE[/]\nclear - clear cmd/terminal"],
}
box = Item("box", ["An odd box", "There are no markings on the cardboard box. It looks like it's been sitting in the forest for a while."], {"sellprice": 100, "buyprice": 150})
startroom = Room("Crossroads", ["A crossroads between a mountain, a forest, a town, and a plains.", "To the west is a mountain that looms in the distance.\nTo the north is a town named <TODO: name town>.\nTo the east is a bridge over a river, leading to a path that trails off into the distance.\nTo the south is the dark forest you came out of."], {"s": "ft1"}, {}, {})
foresttrail1 = Room("Forest Trail", ["A dark trail that leads to a clearing to the south and a crossroads to the north.", "This place gives you the chills.\nTo the north is a crossroads between two trails.\nTo the south is a rocky clearing."], {"n": "sr"}, {"bx": box}, {})
allrooms = {
    "sr": startroom,
    "ft1": foresttrail1,
}
rprint(align.Align(f"[b green]{title}[/]", "center").center(f"[bold green]{title}[/]"))
rprint(align.Align(f"[b]V{version}[/]", "center").center(f"[b]V{version}[/]"))
name = input("What is your adventurer's name? ")
initplayer(name, startroom)
while True:
    room = player["loc"]
    rprint(room.passive)
    command = input(f"{player['name']}> ").split()
    #list commands
    if command == ["help"]:
        for command in commands:
            rprint(f"{command} - {commands[command][0]}")
        print()
    #detailed help for specific command
    elif command[0] == "help" and len(command) >= 2:
        rprint(f"{commands[command[1]][1]}\n")
    #look around
    elif command == ["look"]:
        rprint(room.detail)
        for item in room.items:
            rprint(f"There is a {room.items[item].name} here.")
        rprint()
    #movement
    elif command[0][0] in list(room.directions.keys()) and command[0] in ["north", "west", "east", "south", "up", "down", "n", "w", "e", "s", "u", "d"]:
        player["loc"] = allrooms[room.directions[command[0][0]]]
    #if the player tries to move in a direction that they can't
    elif command[0] in ["north", "west", "east", "south", "up", "down", "n", "w", "e", "s", "u", "d"]:
        if len(command[0]) == 1:
            tmpconvert = {"n": "north", "w": "west", "e": "east", "s": "south", "u": "up", "d": "down"}
            rprint(f"[red]You cannot go {tmpconvert[command[0]]}")
        else:
            rprint(f"[red]You cannot go {command[0]}.")
    #grab items
    elif command[0] == "grab" and len(command) >= 2:
        items = {room.items[item].name:room.items[item] for item in room.items}
        if command[1] in items:
            item = items[command[1]]
            internalname = list(room.items.keys())[list(items.values()).index(item)]
            player["inventory"][internalname] = item
            room.items.pop(internalname)
            rprint(f"[blue]{command[1]} grabbed!")
        #let this code stand as a memorial of what not to do
        #item = [room.items[item] for item in room.items][[room.items[item].name for item in room.items].index(command[1].lower())]
        #itemname = list(room.items.keys())[list(room.items.values()).index(item)]
        #player["inventory"][itemname] = item
        #room.items[itemname].pop()
    #unspecified item
    elif command == ["grab"]:
        rprint("[red]grab what?")
    #drop items
    elif command[0] == "drop" and len(command) >= 2:
        items = {player["inventory"][item].name:player["inventory"][item] for item in player["inventory"]}
        if command[1] in items:
            item = items[command[1]]
            internalname = list(player["inventory"].keys())[list(items.values()).index(item)]
            room.items[internalname] = item
            player["inventory"].pop(internalname)
            rprint(f"[blue]{command[1]} dropped!")
    #unspecified item
    elif command == ["drop"]:
        rprint("[red]drop what?")
    #see detailed description of item in inventory
    elif command[0] == "inspect" and len(command) == 2:
        items = {player["inventory"][item].name:player["inventory"][item] for item in player["inventory"]}
        if command[1] in items:
            rprint(f"[b]{items[command[1]].name.upper()}[/]\n{items[command[1]].long}")
    #unspecified item
    elif command == ["inspect"]:
        rprint("[red]inspect what?")
    #see inventory
    elif command == ["inventory"] or command == ["i"]:
        for i in player["inventory"]:
            item = player["inventory"][i]
            rprint(f"{item.name} - {item.short}")
    #clear terminal/cmd prompt
    elif command == ["clear"]:
        os.system("cls||clear") #multiplatform clear command!
        rprint("[green]cleared!")
    #quit game
    elif command == ["quit"] or command == ["q"]:
        break
    #find a similar command
    else:
        rprint(f"[red]Command not found. Do you mean '{findsimilar(command[0], list(commands.keys()))}'?")

also:
nope@pop-os:~/Documents/littlescripts/myrpg$ file v3rpg.py
v3rpg.py: Python script, ASCII text executable, with very long lines
the description of the script sounds sus but it actually isn't

the long lines are mostly just descriptions

Last edited by ScratchCatHELLO (June 23, 2021 23:22:57)






ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

rich.align's documentation is super confusing so I had to open one of the test scripts from the source code to figure out the syntax





ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

PyRPG v0.2 (BETA) - The Feedback and Consistency Update
use the “changelog” command on this version and any higher version to see the changes from the update

#iteration 3
import os
import random
from difflib import SequenceMatcher
from rich import print as rprint
from rich import align
version = "0.2 (BETA)"
#blue   = inventory
#red    = error/invalid command
#orange = combat?
#green  = outside-game messages (changelog, clearing, quit prompt)
class Room:
    """
    Represents a room.
    Attributes
    ----------
    name : str
        the room name (used in dev mode)
    passive : str
        the description that displays after each turn
    detail : str
        the description that displays when you type "look"
    directions : list
        a list of directions a player in the room can move
    items : dict
        a list of item objects
    ents : dict
        a list of entity objects
    Methods
    -------
    ritem(itemname):
        removes an item by name
    rent(entname):
        removes an entity by name
    str(room):
        converts a room into a string listing attributes
    """
    def __init__(room, name, descriptions, directions, items, ents):
        room.name = name
        room.passive = descriptions[0]
        room.detail = descriptions[1]
        room.directions = directions
        room.items = items
        room.ents = ents
    def __str__(room):
        tmpstr = f"{room.name} "
        for item in room.items:
            tmpstr += f"D There is a {item.name}.\n"
        for ent in room.ents:
            tmpstr += f"D A {ent.name} is standing here.\n"
        return tmpstr
    def ritem(room, itemname):
        room.items.pop(itemname)
    def rent(room, entname):
        room.items.pop(entname)
class Item:
    """
    Represents an item.
    Attributes
    ----------
    name : str
        the item name
    short : str
        short description of the item
    long : str
        detailed description of the item
    stats : dict
        a list of stats
        structure is as follows:
        {
            "dmg": 10, #damage of the item
            "critdmg": 15, #damage of the item when it hits something critically
            "sellprice": 30, #sell value
            "buyprice": 35, #buy value
            "atkeffect": randomdmg #executes a function when you use the item to attack
        }
    weapon : bool
        False -> not a weapon
        True -> a weapon
        defaults to False
    """
    def __init__(item, name, descriptions, stats, weapon=False):
        item.name = name
        item.d = descriptions
        item.short = descriptions[0] #brief
        item.long = descriptions[1] #detail
        item.stats = stats
        item.weapon = weapon
class Ent:
    """
    Represents an entity.
    Attributes
    ----------
    name : str
        the entity name
    inv : dict
        the inventory of the entity. consists of a dict of Item objects
    stats : dict
        the stats of the entity
        structure is as follows:
        {
            "hp": 10, #current health
            "maxhp": 10, #full health
            "dmg": 5, #its damage in combat
            "acc": 2, #entity will hit (1/acc)*100 percent of the time
            "crit": 5, #entity will crit (1/crit)*100 percent of the time
            "critdmg": 7, #damage of a critical hit
        }
    hostilemode : int
        whether an entity will attack unprovoked
        2: the entity will attack when the player enters the room it's in
        1: the entity won't fight unprovoked
        0: the entity won't fight
    """
    def __init__(ent, name, inv, stats, hostilemode=1):
        ent.name = name
        ent.inv = inv
        ent.stats = stats
        ent.hostilemode = hostilemode
    def giveitem(ent, player, itemname):
        player["inv"][itemname] = ent.inv[itemname]
        ent.inv[itemname].pop()
    def damage(ent, amount):
        if ent.stats["hp"] - amount < 0:
            ent.stats["hp"] = 0
        else:
            ent.stats["hp"] -= amount
    def heal(ent, amount):
        if ent.stats["hp"] + amount > ent.stats["maxhp"]:
            ent.stats["hp"] = ent.stats["maxhp"]
        else:
            ent.stats["hp"] += amount
    def attack(ent):
        stats = ent.stats
        hitper = (1/stats["acc"])*100
        critper = (1/stats["crit"])*100
        if bool(random.choices([1, 0], weights=[hitper, 100-hitper])[0]):
            if bool(random.choices([1, 0], weights=[critper, 100-critper])[0]):
                rprint(f"!![bold red]The {ent.name} critically hit you, doing {stats['critdmg']} damage!")
                return stats["critdmg"]
            else:
                rprint(f"! [bold]The {ent.name} hit you, doing {stats['dmg']} damage!")
                return stats["dmg"]
        else:
            rprint(f"  [italic]The {ent.name} missed!")
            return 0
title = """      :::::::::  :::   ::: :::::::::  :::::::::   ::::::::
     :+:    :+: :+:   :+: :+:    :+: :+:    :+: :+:    :+:
    +:+    +:+  +:+ +:+  +:+    +:+ +:+    +:+ +:+
   +#++:++#+    +#++:   +#++:++#:  +#++:++#+  :#:
  +#+           +#+    +#+    +#+ +#+        +#+   +#+#
 #+#           #+#    #+#    #+# #+#        #+#    #+#
###           ###    ###    ### ###         ########       """
versions = {
    "0.1 (BETA)": """[b green]0.1[/]\n - first version of game\n - added look, help, movement commands, grab/drop, inventory, inspect, clear, quit\n - added first map (two rooms with an item in one)\n""",
    "0.2 (BETA)": """[green][b]0.2[/]\n[i dim]The Feedback and Consistency Update[/][/green]\n - added changelog\n - fixed typos\n - consistent capitalization\n - 'inventory' now tells you when your inventory is empty\n - 'grab' and 'drop' now warn you when the item isn't in the room or your inventory, respectively.\n"""
}
commands = {
    "help": ["print list of commands and descriptions.", "[b]=HELP=[/]\nPrints a list of command and simple descriptions.\n[b]USAGE[/]\nhelp - print list of commands and descriptions\n    command (opt) - print detailed description of the specified command."],
    "help <command>": ["print detailed explanation of <command>."],
    "quit": ["quit game.", "[b]=QUIT=[/]\nExits the game.\n[b]USAGE[/]\nquit - end game\nq - end game"],
    "look": ["look around at the current room.", "[b]=LOOK=[/]\nPrints a detailed description of the current room.\n[b]USAGE[/]\nlook - see description of current room"],
    "north": ["go north.", "[b]=NORTH=[/]\nMoves the player north.\n[b]USAGE[/]\nnorth - move player north\nn - move player north"],
    "west": ["go west.", "[b]=WEST=[/]\nMoves the player west.\n[b]USAGE[/]\nwest - move player west\nw - move player west"],
    "east": ["go east.", "[b]=EAST=[/]\nMoves the player east.\n[b]USAGE[/]\neast - move player east\ne - move player east"],
    "south": ["go south.", "[b]=WEST=[/]\nMoves the player south.\n[b]USAGE[/]\nwest - move player south\ns - move player south"],
    "grab": ["grab item from room.", "[b]=GRAB=[/]\nGrab an item out of the room and place it in your inventory.\n[b]USAGE[/]\ngrab - grab an item\n    item - name of item to grab."],
    "drop": ["drop item into room.", "[b]=DROP=[/]\nDrop an item from your inventory and place it in the room.\n[b]USAGE[/]\ndrop - drop an item\n    item - name of item to drop."],
    "inventory": ["list items in inventory.", "[b]=INVENTORY=[/]\nPrint a list of items in the player's inventory.\n[b]USAGE[/]\ninventory/i - read inventory"],
    "inspect": ["show detailed description of an item.", "[b]=INSPECT=[/]\nShow a detailed description of an item in your inventory.\n[b]USAGE[/]\ninspect - show long item description"],
    "clear": ["clear cmd prompt/terminal.", "[b]=CLEAR=[/]\nClear screen (for when the terminal has a lot of text in it).\n[b]USAGE[/]\nclear - clear cmd/terminal"],
    "changelog": ["show changelog for the current rpg version.", "[b]=CHANGELOG=[/]\nShow version changelog.\n[b]USAGE[/]\nchangelog - show changelog for the current version\n    version (opt) - print changelog for specific version"],
    "changelog <version>": ["show changelog for a specific rpg version."]
}
#find the item of a list that is closest to a string
def findsimilar(thing, inlist):
    similar = {}
    for item in inlist:
        similar[item] = SequenceMatcher(None, item, thing).ratio()
    return list(reversed(sorted(similar.items(),key=lambda x:x[1])))[0][0]
player = {}
def initplayer(name, startroom):
    global player
    player = {
        "name": name,
        "loc": startroom,
        "hp": 30,
        "maxhp": 30,
        "inventory": {}
    }
def noeffect():
    pass
box = Item("box", ["An odd box", "There are no markings on the cardboard box. It looks like it's been sitting in the forest for a while."], {"sellprice": 100, "buyprice": 150})
startroom = Room("Crossroads", ["A crossroads between a mountain, a forest, a town, and a plains.", "To the west is a mountain that looms in the distance.\nTo the north is a town named <TODO: name town>.\nTo the east is a bridge over a river, leading to a path that trails off into the distance.\nTo the south is the dark forest you came out of."], {"s": "ft1"}, {}, {})
foresttrail1 = Room("Forest Trail", ["A dark trail that leads to a clearing to the south and a crossroads to the north.", "This place gives you the chills.\nTo the north is a crossroads between two trails.\nTo the south is a rocky clearing."], {"n": "sr"}, {"bx": box}, {})
allrooms = {
    "sr": startroom,
    "ft1": foresttrail1,
}
rprint(align.Align(f"[b green]{title}[/]", "center").center(f"[bold green]{title}[/]"))
rprint(align.Align(f"[b]V{version}[/]", "center").center(f"[b]V{version}[/]"))
name = input("What is your adventurer's name? ")
initplayer(name, startroom)
while True:
    room = player["loc"]
    rprint(room.passive)
    command = input(f"\n{player['name']}> ").split()
    #list commands
    if command == ["help"]:
        for command in commands:
            rprint(f"{command} - {commands[command][0]}")
        print()
    #detailed help for specific command
    elif command[0] == "help" and len(command) >= 2:
        rprint(f"{commands[command[1]][1]}\n")
    #look around
    elif command == ["look"]:
        rprint(room.detail)
        for item in room.items:
            rprint(f"There is a {room.items[item].name} here.")
        rprint()
    #movement
    elif command[0][0] in list(room.directions.keys()) and command[0] in ["north", "west", "east", "south", "up", "down", "n", "w", "e", "s", "u", "d"]:
        player["loc"] = allrooms[room.directions[command[0][0]]]
    #if the player tries to move in a direction that they can't
    elif command[0] in ["north", "west", "east", "south", "up", "down", "n", "w", "e", "s", "u", "d"]:
        if len(command[0]) == 1:
            tmpconvert = {"n": "north", "w": "west", "e": "east", "s": "south", "u": "up", "d": "down"}
            rprint(f"[red]You cannot go {tmpconvert[command[0]]}.")
        else:
            rprint(f"[red]You cannot go {command[0]}.")
    #grab items
    elif command[0] == "grab" and len(command) >= 2:
        items = {room.items[item].name:room.items[item] for item in room.items}
        if command[1] in items:
            item = items[command[1]]
            internalname = list(room.items.keys())[list(items.values()).index(item)]
            player["inventory"][internalname] = item
            room.items.pop(internalname)
            rprint(f"[blue_violet]{command[1]} grabbed!")
        else:
            if not len(items) == 0:
                rprint(f"[red]There is no {command[1]} here! There [i]is[/] a {findsimilar(command[1], items)} here. Did you mean that?")
            else:
                rprint(f"[red]There are no items here!")
        #let this code stand as a memorial of what not to do
        #item = [room.items[item] for item in room.items][[room.items[item].name for item in room.items].index(command[1].lower())]
        #itemname = list(room.items.keys())[list(room.items.values()).index(item)]
        #player["inventory"][itemname] = item
        #room.items[itemname].pop()
    #unspecified item
    elif command == ["grab"]:
        rprint("[red]Grab what?")
    #drop items
    elif command[0] == "drop" and len(command) >= 2:
        items = {player["inventory"][item].name:player["inventory"][item] for item in player["inventory"]}
        if command[1] in items:
            item = items[command[1]]
            internalname = list(player["inventory"].keys())[list(items.values()).index(item)]
            room.items[internalname] = item
            player["inventory"].pop(internalname)
            rprint(f"[blue_violet]{command[1]} dropped!")
        else:
            if not len(items) == 0:
                rprint(f"[red]There is no {command[1]} in your inventory! There [i]is[/] a {findsimilar(command[1], items)} in your inventory. Did you mean that?")
            else:
                rprint(f"[red]You don't have any items to drop!")
    #unspecified item
    elif command == ["drop"]:
        rprint("[red]Drop what?")
    #see detailed description of item in inventory
    elif command[0] == "inspect" and len(command) == 2:
        items = {player["inventory"][item].name:player["inventory"][item] for item in player["inventory"]}
        if command[1] in items:
            rprint(f"[b blue_violet]{items[command[1]].name.upper()}[/]\n[pale_turquoise1]{items[command[1]].long}[/]")
    #unspecified item
    elif command == ["inspect"]:
        rprint("[red]Inspect what?")
    #see inventory
    elif command == ["inventory"] or command == ["i"]:
        for i in player["inventory"]:
            item = player["inventory"][i]
            rprint(f"[b blue_violet]{item.name}[/] [b]-[/] [i pale_turquoise1]{item.short}[/]")
        if len(player["inventory"]) == 0:
            rprint("[red]Your inventory is empty!")
    #clear terminal/cmd prompt
    elif command == ["clear"]:
        os.system("cls||clear") #multiplatform clear command!
        rprint("[green]Cleared!")
    #changelog
    elif command == ["changelog"]:
        rprint(versions[version])
    #access specific changelog
    elif command[0] == "changelog" and len(command) >= 2:
        #reassamble version names that have spaces
        name = " ".join(command[1:len(command)])
        try:
            rprint(versions[name])
        #if the version doesn't exist, find a similar one
        except KeyError:
            rprint(f"[red]'{name}' is not a valid version name. Did you mean '{findsimilar(name, list(versions.keys()))}'?")
    #quit game
    elif command == ["quit"] or command == ["q"]:
        rprint("[b green]Are you [i]sure[/i]?[/b green] (Y/n)")
        ynprompt = input().lower()
        if ynprompt in ["y", "yes"]:
            rprint("[green]Quitting game...")
            break
        elif ynprompt in ["n", "no", "nevermind"]:
            continue
        else:
            rprint("[red]Sorry, I don't understand. Can you try again? Valid answers are 'Y', 'Yes', 'N', 'No' (Case insensitive).")
    #find a similar command
    else:
        rprint(f"[red]Command not found. Did you mean '{findsimilar(command[0], list(commands.keys()))}'?")





ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

redacted@pop-os:~/none_of/your/business$ wc v3rpg.py
346 1689 15056 v3rpg.py
uh oh
it seems the script is fast approaching the character limit
or was the character limit 200,000?
I might have to get a github account soon





ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
zahmbie1
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

nunya@pop-os:~/some/path$ python3.9 v3rpg.py
::::::::: ::: ::: ::::::::: ::::::::: ::::::::
:+: :+: :+: :+: :+: :+: :+: :+: :+: :+:
+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
+#++:++#+ +#++: +#++:++#: +#++:++#+ :#:
+#+ +#+ +#+ +#+ +#+ +#+ +#+#
#+# #+# #+# #+# #+# #+# #+#
### ### ### ### ### ########
V0.3 (BETA)
What is your adventurer's name? Johnus Doeus
A crossroads between a mountain, a forest, a town, and a plains.

Johnus Doeus> s
A dark trail that leads to a clearing to the south and a crossroads to the north.

Johnus Doeus> grab box
box grabbed!
A dark trail that leads to a clearing to the south and a crossroads to the north.

Johnus Doeus> i
box - An odd box
A dark trail that leads to a clearing to the south and a crossroads to the north.

Johnus Doeus> inspect box
BOX
There are no markings on the cardboard box. It looks like it's been sitting in the forest for a while.
A dark trail that leads to a clearing to the south and a crossroads to the north.

Johnus Doeus> n
A crossroads between a mountain, a forest, a town, and a plains.

Johnus Doeus> use box to open
You open the box. There's a sword inside!
You now have a sword!
A crossroads between a mountain, a forest, a town, and a plains.

Johnus Doeus> drop box
box dropped!
A crossroads between a mountain, a forest, a town, and a plains.

Johnus Doeus> i
sword - An elven sword
A crossroads between a mountain, a forest, a town, and a plains.

Johnus Doeus> inspect sword
SWORD
There are a variety of runes inscribed in the sword. The edges of the blade seem to glow slightly. How cliche.
A crossroads between a mountain, a forest, a town, and a plains.

Johnus Doeus> look
To the west is a mountain that looms in the distance.
To the north is a town named <TODO: name town>.
To the east is a bridge over a river, leading to a path that trails off into the distance.
To the south is the dark forest you came out of.
There is a box here.

A crossroads between a mountain, a forest, a town, and a plains.

Johnus Doeus>





ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

PyRPG v0.3 (BETA) - The Item Update
added “use”, which allows you to do stuff using items (it sounds vague because it is)

#iteration 3
import os
import random
from difflib import SequenceMatcher
from rich import print as rprint
from rich import align
version = "0.3 (BETA)"
#blue   = inventory
#purple = item uses
#red    = error/invalid command
#orange = combat?
#green  = outside-game messages (changelog, clearing, quit prompt)
class Room:
    """
    Represents a room.
    Attributes
    ----------
    name : str
        the room name (used in dev mode)
    passive : str
        the description that displays after each turn
    detail : str
        the description that displays when you type "look"
    directions : list
        a list of directions a player in the room can move
    items : dict
        a list of item objects
    ents : dict
        a list of entity objects
    Methods
    -------
    ritem(itemname):
        removes an item by name
    rent(entname):
        removes an entity by name
    str(room):
        converts a room into a string listing attributes
    """
    def __init__(room, name, descriptions, directions, items, ents):
        room.name = name
        room.passive = descriptions[0]
        room.detail = descriptions[1]
        room.directions = directions
        room.items = items
        room.ents = ents
    def __str__(room):
        tmpstr = f"{room.name} "
        for item in room.items:
            tmpstr += f"D There is a {item.name}.\n"
        for ent in room.ents:
            tmpstr += f"D A {ent.name} is standing here.\n"
        return tmpstr
    def ritem(room, itemname):
        room.items.pop(itemname)
    def rent(room, entname):
        room.items.pop(entname)
class Item:
    """
    Represents an item.
    Attributes
    ----------
    name : str
        the item name
    short : str
        short description of the item
    long : str
        detailed description of the item
    stats : dict
        a list of stats
        structure is as follows:
        {
            "dmg": 10, #damage of the item
            "critdmg": 15, #damage of the item when it hits something critically
            "sellprice": 30, #sell value
            "buyprice": 35, #buy value
            "atkeffect": randomdmg #executes a function when you use the item to attack
        }
    special : dict (optional)
        a list of actions that can be performed using an item
        toaster:
        {
            "toast bread": ["toast your bread", toast, "bread"],
            "toast bagel": ["toast your bagel", "toast, "bagel"]
        }
        use toaster to toast bread - executes toast("bread")
        use toaster to toast bagel - executes toast("bagel")
        use toaster instructions - prints the following:
            toast bread - toast your bread
            toast bagel - toast your bagel
        syntax:
        {
            "subcommand": ["description", function, "arg1", "arg2", "arg3"]
        }
    weapon : bool (optional)
        False -> not a weapon
        True -> a weapon
        defaults to False
    """
    def __init__(item, name, descriptions, stats, special={}, weapon=False):
        item.name = name
        item.d = descriptions
        item.short = descriptions[0] #brief
        item.long = descriptions[1] #detail
        item.stats = stats
        item.special = special
        item.weapon = weapon
class Ent:
    """
    Represents an entity.
    Attributes
    ----------
    name : str
        the entity name
    inv : dict
        the inventory of the entity. consists of a dict of Item objects
    stats : dict
        the stats of the entity
        structure is as follows:
        {
            "hp": 10, #current health
            "maxhp": 10, #full health
            "dmg": 5, #its damage in combat
            "acc": 2, #entity will hit (1/acc)*100 percent of the time
            "crit": 5, #entity will crit (1/crit)*100 percent of the time
            "critdmg": 7, #damage of a critical hit
        }
    hostilemode : int
        whether an entity will attack unprovoked
        2: the entity will attack when the player enters the room it's in
        1: the entity won't fight unprovoked
        0: the entity won't fight
    """
    def __init__(ent, name, inv, stats, hostilemode=1):
        ent.name = name
        ent.inv = inv
        ent.stats = stats
        ent.hostilemode = hostilemode
    def giveitem(ent, player, itemname):
        player["inv"][itemname] = ent.inv[itemname]
        ent.inv[itemname].pop()
    def damage(ent, amount):
        if ent.stats["hp"] - amount < 0:
            ent.stats["hp"] = 0
        else:
            ent.stats["hp"] -= amount
    def heal(ent, amount):
        if ent.stats["hp"] + amount > ent.stats["maxhp"]:
            ent.stats["hp"] = ent.stats["maxhp"]
        else:
            ent.stats["hp"] += amount
    def attack(ent):
        stats = ent.stats
        hitper = (1/stats["acc"])*100
        critper = (1/stats["crit"])*100
        if bool(random.choices([1, 0], weights=[hitper, 100-hitper])[0]):
            if bool(random.choices([1, 0], weights=[critper, 100-critper])[0]):
                rprint(f"!![bold red]The {ent.name} critically hit you, doing {stats['critdmg']} damage!")
                return stats["critdmg"]
            else:
                rprint(f"! [bold]The {ent.name} hit you, doing {stats['dmg']} damage!")
                return stats["dmg"]
        else:
            rprint(f"  [italic]The {ent.name} missed!")
            return 0
title = """      :::::::::  :::   ::: :::::::::  :::::::::   ::::::::
     :+:    :+: :+:   :+: :+:    :+: :+:    :+: :+:    :+:
    +:+    +:+  +:+ +:+  +:+    +:+ +:+    +:+ +:+
   +#++:++#+    +#++:   +#++:++#:  +#++:++#+  :#:
  +#+           +#+    +#+    +#+ +#+        +#+   +#+#
 #+#           #+#    #+#    #+# #+#        #+#    #+#
###           ###    ###    ### ###         ########       """
versions = {
    "0.1 (BETA)": "[b green]0.1[/]\n - first version of game\n - added look, help, movement commands, grab/drop, inventory, inspect, clear, quit\n - added first map (two rooms with an item in one)\n",
    "0.2 (BETA)": "[green][b]0.2[/]\n[i dim]The Feedback and Consistency Update[/][/green]\n - added changelog\n - fixed typos\n - consistent capitalization\n - 'inventory' now tells you when your inventory is empty\n - 'grab' and 'drop' now warn you when the item isn't in the room or your inventory, respectively.\n",
    "0.3 (BETA)": "[green][b]0.3[/]\n[i dim]The Items Update[/][/green]\n - added 'use' (this sounds small, but it's actually pretty big)\n - box can now be opened using the 'use' command"
}
commands = {
    "help": ["print list of commands and descriptions.", "[b]=HELP=[/]\nPrints a list of command and simple descriptions.\n[b]USAGE[/]\nhelp - print list of commands and descriptions\n    command (opt) - print detailed description of the specified command."],
    "help <command>": ["print detailed explanation of <command>."],
    "quit": ["quit game.", "[b]=QUIT=[/]\nExits the game.\n[b]USAGE[/]\nquit - end game\nq - end game"],
    "look": ["look around at the current room.", "[b]=LOOK=[/]\nPrints a detailed description of the current room.\n[b]USAGE[/]\nlook - see description of current room"],
    "north": ["go north.", "[b]=NORTH=[/]\nMoves the player north.\n[b]USAGE[/]\nnorth - move player north\nn - move player north"],
    "west": ["go west.", "[b]=WEST=[/]\nMoves the player west.\n[b]USAGE[/]\nwest - move player west\nw - move player west"],
    "east": ["go east.", "[b]=EAST=[/]\nMoves the player east.\n[b]USAGE[/]\neast - move player east\ne - move player east"],
    "south": ["go south.", "[b]=WEST=[/]\nMoves the player south.\n[b]USAGE[/]\nwest - move player south\ns - move player south"],
    "grab": ["grab item from room.", "[b]=GRAB=[/]\nGrab an item out of the room and place it in your inventory.\n[b]USAGE[/]\ngrab - grab an item\n    item - name of item to grab."],
    "drop": ["drop item into room.", "[b]=DROP=[/]\nDrop an item from your inventory and place it in the room.\n[b]USAGE[/]\ndrop - drop an item\n    item - name of item to drop."],
    "inventory": ["list items in inventory.", "[b]=INVENTORY=[/]\nPrint a list of items in your inventory.\n[b]USAGE[/]\ninventory/i - read inventory"],
    "inspect": ["show detailed description of an item.", "[b]=INSPECT=[/]\nShow a detailed description of an item in your inventory.\n[b]USAGE[/]\ninspect - show long item description"],
    "clear": ["clear cmd prompt/terminal.", "[b]=CLEAR=[/]\nClear screen (for when the terminal has a lot of text in it).\n[b]USAGE[/]\nclear - clear cmd/terminal"],
    "changelog": ["show changelog for the current rpg version.", "[b]=CHANGELOG=[/]\nShow version changelog.\n[b]USAGE[/]\nchangelog - show changelog for the current version\n    version (opt) - print changelog for specific version"],
    "changelog <version>": ["show changelog for a specific rpg version."],
    "use": ["use an item to do something.", "[b]=USE=[/]\nPerform an action using an item in your inventory\n[b]USAGE[/]\nuse - perform an action using an item\n    item - the item to use\n        to - use an item to do something\n            action - what to use the item for\n        instructions - get a list of things the item can do"]
}
#find the item of a list that is closest to a string
def findsimilar(thing, inlist):
    similar = {}
    for item in inlist:
        similar[item] = SequenceMatcher(None, item, thing).ratio()
    return list(reversed(sorted(similar.items(),key=lambda x:x[1])))[0][0]
player = {}
def initplayer(name, startroom):
    global player
    player = {
        "name": name,
        "loc": startroom,
        "hp": 30,
        "maxhp": 30,
        "inventory": {}
    }
def openbox():
    sword = Item("sword", ["An elven sword", "There are a variety of runes inscribed in the sword. The edges of the blade seem to glow slightly. How cliche."], {"sellprice": 90, "buyprice": 100})
    player["inventory"]["sword"] = sword
    rprint("You open the box. There's a sword inside!")
    rprint("[blue]You now have a [b]sword[/]!")
def noeffect():
    pass
box = Item("box", ["An odd box", "There are no markings on the cardboard box. It looks like it's been sitting in the forest for a while."], {"sellprice": 100, "buyprice": 150}, {"open": ["open the box", openbox]})
startroom = Room("Crossroads", ["A crossroads between a mountain, a forest, a town, and a plains.", "To the west is a mountain that looms in the distance.\nTo the north is a town named <TODO: name town>.\nTo the east is a bridge over a river, leading to a path that trails off into the distance.\nTo the south is the dark forest you came out of."], {"s": "ft1"}, {}, {})
foresttrail1 = Room("Forest Trail", ["A dark trail that leads to a clearing to the south and a crossroads to the north.", "This place gives you the chills.\nTo the north is a crossroads between two trails.\nTo the south is a rocky clearing."], {"n": "sr"}, {"bx": box}, {})
allrooms = {
    "sr": startroom,
    "ft1": foresttrail1,
}
rprint(align.Align(f"[b green]{title}[/]", "center").center(f"[bold green]{title}[/]"))
rprint(align.Align(f"[b]V{version}[/]", "center").center(f"[b]V{version}[/]"))
name = input("What is your adventurer's name? ")
initplayer(name, startroom)
while True:
    room = player["loc"]
    rprint(room.passive)
    command = input(f"\n{player['name']}> ").split()
    #list commands
    if command == ["help"]:
        for command in commands:
            rprint(f"{command} - {commands[command][0]}")
        print()
    #detailed help for specific command
    elif command[0] == "help" and len(command) >= 2:
        rprint(f"{commands[command[1]][1]}\n")
    #look around
    elif command == ["look"]:
        rprint(room.detail)
        for item in room.items:
            rprint(f"There is a {room.items[item].name} here.")
        rprint()
    #movement
    elif command[0][0] in list(room.directions.keys()) and command[0] in ["north", "west", "east", "south", "up", "down", "n", "w", "e", "s", "u", "d"]:
        player["loc"] = allrooms[room.directions[command[0][0]]]
    #if the player tries to move in a direction that they can't
    elif command[0] in ["north", "west", "east", "south", "up", "down", "n", "w", "e", "s", "u", "d"]:
        if len(command[0]) == 1:
            tmpconvert = {"n": "north", "w": "west", "e": "east", "s": "south", "u": "up", "d": "down"}
            rprint(f"[red]You cannot go {tmpconvert[command[0]]}.")
        else:
            rprint(f"[red]You cannot go {command[0]}.")
    #grab items
    elif command[0] == "grab" and len(command) >= 2:
        items = {room.items[item].name:room.items[item] for item in room.items}
        if command[1] in items:
            item = items[command[1]]
            internalname = list(room.items.keys())[list(items.values()).index(item)]
            player["inventory"][internalname] = item
            room.items.pop(internalname)
            rprint(f"[blue]{command[1]} grabbed!")
        else:
            if not len(items) == 0:
                rprint(f"[red]There is no {command[1]} here! There [i]is[/] a {findsimilar(command[1], items)} here. Did you mean that?")
            else:
                rprint(f"[red]There are no items here!")
        #let this code stand as a memorial of what not to do
        #item = [room.items[item] for item in room.items][[room.items[item].name for item in room.items].index(command[1].lower())]
        #itemname = list(room.items.keys())[list(room.items.values()).index(item)]
        #player["inventory"][itemname] = item
        #room.items[itemname].pop()
    #unspecified item
    elif command == ["grab"]:
        rprint("[red]Grab what?")
    #drop items
    elif command[0] == "drop" and len(command) >= 2:
        items = {player["inventory"][item].name:player["inventory"][item] for item in player["inventory"]}
        if command[1] in items:
            item = items[command[1]]
            internalname = list(player["inventory"].keys())[list(items.values()).index(item)]
            room.items[internalname] = item
            player["inventory"].pop(internalname)
            rprint(f"[blue]{command[1]} dropped!")
        else:
            if not len(items) == 0:
                rprint(f"[red]There is no {command[1]} in your inventory! There [i]is[/] a {findsimilar(command[1], items)} in your inventory. Did you mean that?")
            else:
                rprint(f"[red]You don't have any items to drop!")
    #unspecified item
    elif command == ["drop"]:
        rprint("[red]Drop what?")
    #see detailed description of item in inventory
    elif command[0] == "inspect" and len(command) == 2:
        items = {player["inventory"][item].name:player["inventory"][item] for item in player["inventory"]}
        if command[1] in items:
            rprint(f"[b blue]{items[command[1]].name.upper()}[/]\n[pale_turquoise1]{items[command[1]].long}[/]")
    #unspecified item
    elif command == ["inspect"]:
        rprint("[red]Inspect what?")
    #see inventory
    elif command == ["inventory"] or command == ["i"]:
        for i in player["inventory"]:
            item = player["inventory"][i]
            rprint(f"[b blue]{item.name}[/] [b]-[/] [i blue]{item.short}[/]")
        if len(player["inventory"]) == 0:
            rprint("[red]Your inventory is empty!")
    #use an item to perform an action
    elif command[0] == "use" and len(command) >= 2:
        itemname = ""
        inst = ""
        items = {player["inventory"][item].name:player["inventory"][item] for item in player["inventory"]}
        current = 0
        #find item name
        for word in command[1:len(command)]:
            current += 1
            if word in ["to", "instructions"]:
                inst = word
                break
            else:
                itemname += f" {word}"
        #if the player included a "to" or "instructions"
        if inst:
            #if the player has the item
            if itemname.strip() in items:
                item = items[itemname.strip()]
                if inst == "instructions":
                    #print uses
                    for use in item.special:
                        rprint(f"[b purple]{use}[/] [b]-[/] [i purple]{item.special[use][0]}[/]")
                    #if the item has no uses
                    if len(item.special) == 0:
                        rprint(f"[red]The {itemname.strip()} has no uses!")
                elif inst == "to":
                    commandname = ""
                    #find command name
                    for word in command[current+1:len(command)]:
                        commandname += f" {word}"
                    #if the item can perform the action
                    if commandname.strip() in item.special:
                        item.special[commandname.strip()][1](*item.special[commandname.strip()][2:len(item.special)+2])
                    else:
                        #if item cannot perform actions
                        if len(item.special) == 0:
                            rprint(f"[red]The {itemname.strip()} has no uses!")
                        else:
                            #find similar action
                            rprint(f"[red]The {itemname.strip()} cannot be used to {commandname.strip()}! Did you mean '{findsimilar(commandname.strip(), list(item.special.keys()))}?'")
            else:
                rprint(f"[red]You don't have a(n) {itemname.strip()}!")
        else:
            rprint(f"[red]Use {itemname.strip()} to do what?")
    #unspecified item
    elif command == ["use"]:
        rprint("[red]Use what item?")
    #clear terminal/cmd prompt
    elif command == ["clear"]:
        os.system("cls||clear") #multiplatform clear command!
        rprint("[green]Cleared!")
    #changelog
    elif command == ["changelog"]:
        rprint(versions[version])
    #access specific changelog
    elif command[0] == "changelog" and len(command) >= 2:
        #reassamble version names that have spaces
        name = " ".join(command[1:len(command)])
        try:
            rprint(versions[name])
        #if the version doesn't exist, find a similar one
        except KeyError:
            rprint(f"[red]'{name}' is not a valid version name. Did you mean '{findsimilar(name, list(versions.keys()))}'?")
    #quit game
    elif command == ["quit"] or command == ["q"]:
        rprint("[b green]Are you [i]sure[/i]?[/b green] (Y/n)")
        ynprompt = input().lower()
        if ynprompt in ["y", "yes"]:
            rprint("[green]Quitting game...")
            break
        elif ynprompt in ["n", "no", "nevermind"]:
            continue
        else:
            rprint("[red]Sorry, I don't understand. Can you try again? Valid answers are 'Y', 'Yes', 'N', 'No' (Case insensitive).")
    #find a similar command
    else:
        rprint(f"[red]Command not found. Did you mean '{findsimilar(command[0], list(commands.keys()))}'?")





ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

out-of-contest testing:

                           
Achievement Get!
HELLO, WORLD! (6)
Wow, that was really cool
win at amogus

                        
Achievement Get!
IT'S A SMALL WORLD (4)
Minceraft
join the dreamsmp

please don't question my filler text

Last edited by ScratchCatHELLO (June 25, 2021 21:05:57)






ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
zahmbie1
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

this needs to have a list of commands you can do
ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

zahmbie1 wrote:

this needs to have a list of commands you can do

use “help” for a list

here it is anyway:
example> help
help - print list of commands and descriptions.
help <command> - print detailed explanation of <command>.
quit - quit game.
look - look around at the current room.
north - go north.
west - go west.
east - go east.
south - go south.
grab - grab item from room.
drop - drop item into room.
inventory - list items in inventory.
inspect - show detailed description of an item.
clear - clear cmd prompt/terminal.
changelog - show changelog for the current rpg version.
changelog <version> - show changelog for a specific rpg version.
use - use an item to do something.

A crossroads between a mountain, a forest, a town, and a plains.

example>

you can also get more specific help:
example> help use
=USE=
Perform an action using an item in your inventory
USAGE
use - perform an action using an item
item - the item to use
to - use an item to do something
action - what to use the item for
instructions - get a list of things the item can do

A crossroads between a mountain, a forest, a town, and a plains.

example>





ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
zahmbie1
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

ScratchCatHELLO wrote:

zahmbie1 wrote:

this needs to have a list of commands you can do

use “help” for a list

here it is anyway:
example> help
help - print list of commands and descriptions.
help <command> - print detailed explanation of <command>.
quit - quit game.
look - look around at the current room.
north - go north.
west - go west.
east - go east.
south - go south.
grab - grab item from room.
drop - drop item into room.
inventory - list items in inventory.
inspect - show detailed description of an item.
clear - clear cmd prompt/terminal.
changelog - show changelog for the current rpg version.
changelog <version> - show changelog for a specific rpg version.
use - use an item to do something.

A crossroads between a mountain, a forest, a town, and a plains.

example>

you can also get more specific help:
example> help use
=USE=
Perform an action using an item in your inventory
USAGE
use - perform an action using an item
item - the item to use
to - use an item to do something
action - what to use the item for
instructions - get a list of things the item can do

A crossroads between a mountain, a forest, a town, and a plains.

example>
how did i not think of that
also:
cringe>west
command 'west' not found
did you mean: west
ScratchCatHELLO
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

zahmbie1 wrote:

ScratchCatHELLO wrote:

zahmbie1 wrote:

this needs to have a list of commands you can do

use “help” for a list

here it is anyway:
example> help
help - print list of commands and descriptions.
help <command> - print detailed explanation of <command>.
quit - quit game.
look - look around at the current room.
north - go north.
west - go west.
east - go east.
south - go south.
grab - grab item from room.
drop - drop item into room.
inventory - list items in inventory.
inspect - show detailed description of an item.
clear - clear cmd prompt/terminal.
changelog - show changelog for the current rpg version.
changelog <version> - show changelog for a specific rpg version.
use - use an item to do something.

A crossroads between a mountain, a forest, a town, and a plains.

example>

you can also get more specific help:
example> help use
=USE=
Perform an action using an item in your inventory
USAGE
use - perform an action using an item
item - the item to use
to - use an item to do something
action - what to use the item for
instructions - get a list of things the item can do

A crossroads between a mountain, a forest, a town, and a plains.

example>
how did i not think of that
also:
cringe>west
command 'west' not found
did you mean: west

oops I thought it told you when you can’t move a certain way
I guess it doesn’t





ScratchCatHELLO
I have 5600+ posts, I've been on scratch for 5 1/2 years, I'm a Forum Helper™ and I have a Scratch Wiki account!
I like: Python, CSS, Javascript, Rust



Python 3 Text Adventure
cool new browser game - cursed laughing-crying emoji - Illuminati - you know waterbenders, but do you know stock-imagebenders? - snek - vibin' - Bump song (vevo) - Speed bump - yee - fred - m i c k e y
imfh
Scratcher
1000+ posts

PyRPG (Python Text Adventure)

That's cool! A couple tips and ideas for future expansions:

You might want to make it so there are multiple words you can use for the same action. For example, I kept trying to use “examine item” rather than “look at item” since that is what I usually use in other text games. Also, a matter of preference, but you could use command.startswith(“blah”) rather than command[0:4] == “blah”.

It is also handy to have abbreviations for commands, particularly with movement. With Zork, for example, you can just type ‘w’ to go west, which becomes really helpful when the map gets larger. Another common abbreviation is an L for look.

With the map, don't be afraid to make it un-grid-like. What I mean is, when the player travels west along a path, you could make it curve so they have to travel south to return. You can also make one way paths. Stuff like this can make the map more maze like and fun to explore.

When you are making the map, I've sometimes found it easier to draw it on paper first. You can draw a box for each location and connect the boxes using lines. A line on the west side means you go west to travel that path. You can also draw arrows and stuff to indicate one way; you get the idea. Example map from Zork

You might want to consider adding more detail into your “normal” room descriptions so you don't have to type look every time. I usually like to have the descriptions say things like “You are on a north-south path” to make basic directions obvious. If the player isn't necessarily typing look every time, you can also hide some hidden secrets, such as “You notice a small break in the brush to the west.”

Scratch to Pygame converter: https://scratch.mit.edu/discuss/topic/600562/

Powered by DjangoBB