mirror of
https://github.com/tcsenpai/CodeForHonor-Streamline.git
synced 2025-06-04 08:50:04 +00:00
Initial commit
This commit is contained in:
commit
16ad2902e6
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
.DS_Store
|
11
README.md
Normal file
11
README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# CodeForHonor Streamline
|
||||||
|
|
||||||
|
A CLI based game demonstrating the cfo engine capabilities
|
||||||
|
|
||||||
|
## cfo engine
|
||||||
|
|
||||||
|
Powers a great pletora of possible games in pure python by using non blocking sockets for multiplayer communications and intersecated classes
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
This project is totally WIP and lacks documentation
|
7
engine/.vscode/settings.json
vendored
Normal file
7
engine/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"editor.quickSuggestions": {
|
||||||
|
"other": "on",
|
||||||
|
"comments": true,
|
||||||
|
"strings": "off"
|
||||||
|
}
|
||||||
|
}
|
BIN
engine/CFO.png
Normal file
BIN
engine/CFO.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 MiB |
BIN
engine/CFO_midsize.png
Normal file
BIN
engine/CFO_midsize.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 MiB |
BIN
engine/__pycache__/cfo.cpython-39.pyc
Normal file
BIN
engine/__pycache__/cfo.cpython-39.pyc
Normal file
Binary file not shown.
61
engine/cfo.py
Normal file
61
engine/cfo.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
# INFO
|
||||||
|
# This library contains the classes and the relative
|
||||||
|
# methods that will be used in the main code and in game library
|
||||||
|
|
||||||
|
# ANCHOR Character class
|
||||||
|
class Character:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.name = "" # Name of the character
|
||||||
|
self.weapons = []
|
||||||
|
self.max_ep = 100 # Energy points
|
||||||
|
self.max_hp = 100 # Max health points
|
||||||
|
self.protection = 0 # Protection points
|
||||||
|
self.equipment = {
|
||||||
|
"head": None,
|
||||||
|
"arms": None,
|
||||||
|
"body": None,
|
||||||
|
"legs": None,
|
||||||
|
"feet": None,
|
||||||
|
"weapon_dx": None,
|
||||||
|
"weapon_sx": None
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ANCHOR Weapon code class
|
||||||
|
class WeaponCode:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.name = "" # Name of the weapon
|
||||||
|
self.invocation = "" # Invocation of the weapon
|
||||||
|
# True if the weapon is offensive, False if it's defensive or tool
|
||||||
|
self.is_offensive = None
|
||||||
|
self.is_tool = None # True if the weapon is a tool
|
||||||
|
# If the weapon is a tool, the following attributes are not needed
|
||||||
|
self.damage = 0 # Damage of the weapon
|
||||||
|
self.accuracy = 0 # Accuracy of the weapon
|
||||||
|
self.range = 0 # Range of the weapon
|
||||||
|
self.is_ranged = None # True if the weapon is ranged, False if it's melee
|
||||||
|
# Number of ammo rounds (if the weapon is ranged or use energy); -1 means infinite
|
||||||
|
self.rounds_max = 0
|
||||||
|
self.rounds = 0 # Actual rounds loaded
|
||||||
|
self.rounds_per_shoot = 0 # Number of ammo used when shooting
|
||||||
|
# The following attributes are generic
|
||||||
|
self.resistance = 100 # Resistance of the weapon, -1 means infinite
|
||||||
|
self.speed = 0 # Speed of the weapon
|
||||||
|
|
||||||
|
|
||||||
|
# ANCHOR Player class
|
||||||
|
class Player:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.username = "" # Username
|
||||||
|
self.score = 0 # Score of the player
|
||||||
|
# NOTE Character prototype
|
||||||
|
# [character_object, expiration_time]
|
||||||
|
self.characters = [] # List of characters owned by the player
|
||||||
|
self.is_banned = False # True if the player is banned
|
||||||
|
self.is_in_match = False # True if the player is in a match
|
||||||
|
self.last_match = 0 # ID of the last match played or playing
|
||||||
|
|
BIN
engine/data/characters/default/character.cfo
Normal file
BIN
engine/data/characters/default/character.cfo
Normal file
Binary file not shown.
BIN
engine/data/characters/default/weapon
Normal file
BIN
engine/data/characters/default/weapon
Normal file
Binary file not shown.
314
engine/gamelib.py
Normal file
314
engine/gamelib.py
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
# INFO
|
||||||
|
# This library defines the methods used to manage
|
||||||
|
# and work with game sessions and fights
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import pickle
|
||||||
|
import time
|
||||||
|
import socket
|
||||||
|
import fcntl
|
||||||
|
import errno
|
||||||
|
from requests import get
|
||||||
|
import cfo
|
||||||
|
|
||||||
|
# ANCHOR Game class
|
||||||
|
class Game:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
# NOTE Fight server status
|
||||||
|
self.busy = False # True if the player is in a fight
|
||||||
|
self.connected_ip = None # IP of the connected player
|
||||||
|
self.connected_port = None # Port of the connected player
|
||||||
|
# NOTE Network communication variables
|
||||||
|
self.socket = None
|
||||||
|
self.ip = get('https://api.ipify.org').content.decode('utf8')
|
||||||
|
self.port = 9999
|
||||||
|
# NOTE Load the default values for new players and
|
||||||
|
# ensure that the folders are created
|
||||||
|
self.default_character = None
|
||||||
|
self.loaded_characters = [] # List of loaded characters
|
||||||
|
self.default_weapon = None
|
||||||
|
self.loaded_weapons = [] # List of loaded weapons
|
||||||
|
self.initialize()
|
||||||
|
# NOTE Loads players if any or creates a new dictionary
|
||||||
|
if os.path.exists("players.pickle"):
|
||||||
|
with open("players.pickle", "rb") as f:
|
||||||
|
self.players = pickle.load(f)
|
||||||
|
else:
|
||||||
|
self.players = {}
|
||||||
|
# NOTE Current state
|
||||||
|
self.current_player = None
|
||||||
|
self.loaded_character = None
|
||||||
|
# NOTE Match dictionary
|
||||||
|
# {
|
||||||
|
# "match_id" {
|
||||||
|
# "players": [player1, player2],
|
||||||
|
# "characters": [character1, character2],
|
||||||
|
# "turn": 0, # 0 = player1, 1 = player2
|
||||||
|
# "round": 0,
|
||||||
|
# "winner": None
|
||||||
|
# "starting_time": starting_time,
|
||||||
|
# "ending_time": ending_time,
|
||||||
|
# "scores": [score1, score2]
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
self.matches = {}
|
||||||
|
|
||||||
|
# ANCHOR First time initalization / loading of defaults
|
||||||
|
# NOTE This method is called at every restart and creates or loads
|
||||||
|
# the default starting values
|
||||||
|
def initialize(self):
|
||||||
|
# NOE IP and Port initialization
|
||||||
|
self.ip = "127.0.0.1"
|
||||||
|
self.port = 9999
|
||||||
|
# NOTE Folders creation
|
||||||
|
if not (os.path.exists("data")):
|
||||||
|
os.mkdir("data")
|
||||||
|
if not (os.path.exists("data/weapons")):
|
||||||
|
os.mkdir("data/weapons")
|
||||||
|
if not (os.path.exists("data/characters")):
|
||||||
|
os.mkdir("data/characters")
|
||||||
|
if not (os.path.exists("data/players")):
|
||||||
|
os.mkdir("data/players")
|
||||||
|
if not (os.path.exists("data/characters/default")):
|
||||||
|
os.mkdir("data/characters/default")
|
||||||
|
# NOTE Database of objects loading
|
||||||
|
if not (os.path.exists("data/weapons/db.cfo")):
|
||||||
|
with open("data/weapons/db.cfo", "wb") as f:
|
||||||
|
pickle.dump([basic_weapon], f)
|
||||||
|
else:
|
||||||
|
with open("data/weapons/db.cfo", "rb") as f:
|
||||||
|
self.loaded_weapons = pickle.load(f)
|
||||||
|
if not (os.path.exists("data/characters/db.cfo")):
|
||||||
|
with open("data/characters/db.cfo", "wb") as f:
|
||||||
|
pickle.dump([basic_character], f)
|
||||||
|
else:
|
||||||
|
with open("data/characters/db.cfo", "rb") as f:
|
||||||
|
self.loaded_characters = pickle.load(f)
|
||||||
|
# NOTE Default weapon creation
|
||||||
|
if not (os.path.exists("data/characters/default/weapon")):
|
||||||
|
basic_weapon = cfo.WeaponCode()
|
||||||
|
basic_weapon.name = "fist"
|
||||||
|
basic_weapon.invocation = "punch(TARGET)"
|
||||||
|
basic_weapon.is_offensive = True
|
||||||
|
basic_weapon.is_tool = False
|
||||||
|
basic_weapon.resistance = -1
|
||||||
|
basic_weapon.damage = 1
|
||||||
|
basic_weapon.accuracy = 50
|
||||||
|
basic_weapon.is_ranged = False
|
||||||
|
basic_weapon.rounds_max = -1
|
||||||
|
basic_weapon.speed = 1
|
||||||
|
with open("data/characters/default/weapon", "wb") as f:
|
||||||
|
pickle.dump(basic_weapon, f)
|
||||||
|
else:
|
||||||
|
with open("data/characters/default/weapon", "rb") as f:
|
||||||
|
basic_weapon = pickle.load(f)
|
||||||
|
# NOTE Default character creation or loading
|
||||||
|
if not (os.path.exists("data/characters/default/character.cfo")):
|
||||||
|
basic_character = cfo.Character()
|
||||||
|
basic_character.name = "Eddie"
|
||||||
|
basic_character.weapons = [basic_weapon]
|
||||||
|
basic_character.equipment["weapon_dx"] = basic_weapon
|
||||||
|
with open("data/characters/default/character.cfo", "wb") as f:
|
||||||
|
pickle.dump(basic_character, f)
|
||||||
|
else:
|
||||||
|
with open("data/characters/default/character.cfo", "rb") as f:
|
||||||
|
basic_character = pickle.load(f)
|
||||||
|
|
||||||
|
# NOTE Setting the default character and the default weapon
|
||||||
|
self.default_character = basic_character
|
||||||
|
self.default_weapon = basic_weapon
|
||||||
|
|
||||||
|
# ANCHOR Player creation
|
||||||
|
# NOTE A new player has the default character and the default weapon
|
||||||
|
def new_player(self, username):
|
||||||
|
player = cfo.Player()
|
||||||
|
player.username = username
|
||||||
|
player.score = 0
|
||||||
|
player.characters = [self.default_character]
|
||||||
|
player.is_banned = False
|
||||||
|
self.players[username] = player
|
||||||
|
|
||||||
|
# SECTION Utils
|
||||||
|
def execute_function(self, method_name, *args):
|
||||||
|
method = getattr(self, method_name)
|
||||||
|
return method(*args)
|
||||||
|
# !SECTION Utils
|
||||||
|
|
||||||
|
# SECTION Fights
|
||||||
|
def init_fight(self, match_id):
|
||||||
|
# NOTE Environment
|
||||||
|
self.fight_id = match_id
|
||||||
|
# NOTE Match dictionary so we have both
|
||||||
|
# players, both characters and their properties
|
||||||
|
# NOTE Actions dictionary
|
||||||
|
self.actions = {
|
||||||
|
"punch": ["take_damage", 2], # weapon, damage
|
||||||
|
"shield": ["increase_protection", 2], # tool, quantity
|
||||||
|
"shoot": ["take_damage", 2], # weapon, damage
|
||||||
|
"reload": ["reload_weapon", 1], # weapon
|
||||||
|
"heal": ["increase_health", 2], # tool, quantity
|
||||||
|
}
|
||||||
|
|
||||||
|
# SECTION Base events
|
||||||
|
|
||||||
|
def take_damage(self, damage):
|
||||||
|
# NOTE Calculate protection and damage
|
||||||
|
protection = self.current_player.characters[self.loaded_character].protection
|
||||||
|
real_damage = damage - (protection/10)
|
||||||
|
self.current_player.characters[self.loaded_character].hp -= real_damage
|
||||||
|
|
||||||
|
def cure(self, cure):
|
||||||
|
self.current_player.characters[self.loaded_character].hp += cure
|
||||||
|
|
||||||
|
def increase_protection(self, quantity):
|
||||||
|
self.current_player.characters[self.loaded_character].protection += quantity
|
||||||
|
|
||||||
|
def reload_weapon(self, weapon):
|
||||||
|
max_load = self.current_player.characters[self.loaded_character].weapons[weapon].rounds_max
|
||||||
|
# NOTE If the weapon is infinite, we don't reload
|
||||||
|
if max_load == -1:
|
||||||
|
return True
|
||||||
|
# NOTE If the weapon is not infinite, we reload
|
||||||
|
self.current_player.characters[self.loaded_character].weapons[weapon].rounds = max_load
|
||||||
|
|
||||||
|
def increase_health(self, quantity):
|
||||||
|
current_health = self.current_player.characters[self.loaded_character].hp
|
||||||
|
new_health = current_health + quantity
|
||||||
|
max_health = self.current_player.characters[self.loaded_character].max_hp
|
||||||
|
# NOTE If the new health is higher than the max health, we set it to the max health
|
||||||
|
if new_health > max_health:
|
||||||
|
new_health = max_health
|
||||||
|
self.current_player.characters[self.loaded_character].hp = new_health
|
||||||
|
|
||||||
|
# !SECTION Base events
|
||||||
|
|
||||||
|
# TODO Code sender and receiver
|
||||||
|
def send_action(self, action):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def reply_action(self, action):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# NOTE The order of the actions is important
|
||||||
|
# check the below example, receive_action takes
|
||||||
|
# its parameter from listen_to_socket in main cycle
|
||||||
|
def receive_action(self, action):
|
||||||
|
# NOTE Dividing action
|
||||||
|
# REVIEW Ensure that the action is valid
|
||||||
|
is_valid = (
|
||||||
|
action.endswith(")") and
|
||||||
|
"(" in action and not
|
||||||
|
action.startswith("(")
|
||||||
|
)
|
||||||
|
if not is_valid:
|
||||||
|
return False
|
||||||
|
# Actions are composed of a word and two round brackets
|
||||||
|
action = action.split("(")[0]
|
||||||
|
try:
|
||||||
|
arguments = action.split("(")[1].split(")")[0].split(",")
|
||||||
|
if len(arguments) == 0:
|
||||||
|
raise Exception
|
||||||
|
except:
|
||||||
|
arguments = []
|
||||||
|
# Normalizing arguments
|
||||||
|
counter = 0
|
||||||
|
for argument in arguments:
|
||||||
|
argument = argument.strip()
|
||||||
|
arguments[counter] = argument
|
||||||
|
# REVIEW How actions work
|
||||||
|
# Actions are evalued as:
|
||||||
|
# dictionary.get(action)
|
||||||
|
# has [0] = callback, [...]
|
||||||
|
# callback will be then called with arguments
|
||||||
|
# using call-string as a function
|
||||||
|
# TODO To ensure integrity all the items are checked
|
||||||
|
# against our database to get the correct item properties
|
||||||
|
if not action in self.actions:
|
||||||
|
return False
|
||||||
|
result = self.execute_function(self.actions[action][0], *arguments)
|
||||||
|
self.send_to_socket(result)
|
||||||
|
|
||||||
|
# NOTE ip and port are specified in the messages sent
|
||||||
|
def send_to_socket(self, data):
|
||||||
|
if not self.connected_ip or not self.connected_port:
|
||||||
|
return False, "No IP or port specified for the connected player"
|
||||||
|
data = "[" + self.ip + ":" + self.port + "]> " + data
|
||||||
|
sendsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sendsocket.connect((self.connected_ip, self.connected_port))
|
||||||
|
sendsocket.send(data.encode())
|
||||||
|
|
||||||
|
# NOTE This method is called on streamline main file and manages
|
||||||
|
# the whole listen, action and repeat for the duration of
|
||||||
|
# the fight
|
||||||
|
def listen_to_socket(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
msg = self.socket.recv(4096)
|
||||||
|
except socket.error as e:
|
||||||
|
err = e.args[0]
|
||||||
|
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
|
||||||
|
time.sleep(1)
|
||||||
|
# Returns with no data
|
||||||
|
return False, ""
|
||||||
|
else:
|
||||||
|
# a "real" error occurred
|
||||||
|
print(e)
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
decoded = msg.decode()
|
||||||
|
# REVIEW Ensure we can receive one connection per time (same ip)
|
||||||
|
# NOTE You can do this by locking the IP and refusing anything
|
||||||
|
# that is not from that IP
|
||||||
|
#
|
||||||
|
# NOTE Returning this method means the fight is over
|
||||||
|
if not self.busy:
|
||||||
|
self.connected_ip = decoded.split(">")[0].split("[")[
|
||||||
|
1].split(":")[0]
|
||||||
|
self.connected_port = decoded.split(
|
||||||
|
">")[0].split("[")[1].split(":")[1]
|
||||||
|
self.busy = True
|
||||||
|
else:
|
||||||
|
if not self.connected_ip in decoded:
|
||||||
|
# Ignore the message if it's not from the connected player
|
||||||
|
continue
|
||||||
|
# NOTE Decoding the message
|
||||||
|
msg = decoded.split("> ")[1]
|
||||||
|
# Basic actions
|
||||||
|
# REVIEW Implement a method to disconnect clean and not clean to free the slot
|
||||||
|
if msg == "disconnect":
|
||||||
|
self.busy = False
|
||||||
|
self.connected_ip = ""
|
||||||
|
self.connected_port = ""
|
||||||
|
# FIXME the second parameter is to be real
|
||||||
|
return True, 0, "Disconnected"
|
||||||
|
# Execute complex actions
|
||||||
|
self.receive_action(msg)
|
||||||
|
|
||||||
|
def start_socket(self):
|
||||||
|
# Non blocking socket
|
||||||
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.socket.connect(self.ip, self.port)
|
||||||
|
fcntl.fcntl(self.socket, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||||
|
self.listen_to_socket()
|
||||||
|
|
||||||
|
# Example to run and listen in a main cycle
|
||||||
|
#
|
||||||
|
# sock = self.start_socket()
|
||||||
|
# while True:
|
||||||
|
# is_data, data = self.listen_to_socket(sock)
|
||||||
|
# if is_data:
|
||||||
|
# self.receive_action(data)
|
||||||
|
# else:
|
||||||
|
# continue
|
||||||
|
#
|
||||||
|
# # do game stuff
|
||||||
|
|
||||||
|
# SECTION Utils
|
||||||
|
def execute_function(self, method_name, *args):
|
||||||
|
method = getattr(self, method_name)
|
||||||
|
return method(*args)
|
||||||
|
# !SECTION Utils
|
||||||
|
|
||||||
|
# !SECTION Fights
|
BIN
engine/players.pickle
Normal file
BIN
engine/players.pickle
Normal file
Binary file not shown.
143
engine/streamline.py
Normal file
143
engine/streamline.py
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import gamelib
|
||||||
|
|
||||||
|
# SECTION Debug methods
|
||||||
|
|
||||||
|
# SECTION Players selection menu
|
||||||
|
def player_menu(players):
|
||||||
|
valid = False
|
||||||
|
while not valid:
|
||||||
|
print("\n")
|
||||||
|
counter = 0
|
||||||
|
chosable = []
|
||||||
|
for player in players:
|
||||||
|
counter += 1
|
||||||
|
print(str(counter) + ": " + players.get(player).username)
|
||||||
|
chosable.append(players.get(player))
|
||||||
|
print("\n")
|
||||||
|
choice = input("Please select a player: ")
|
||||||
|
# NOTE Sanity check
|
||||||
|
if choice.isdigit():
|
||||||
|
choice = int(choice)
|
||||||
|
if choice <= len(players):
|
||||||
|
current = chosable[choice - 1]
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
print("Invalid choice!")
|
||||||
|
else:
|
||||||
|
print("Invalid choice!")
|
||||||
|
print("\nYou are playing as " + current.username)
|
||||||
|
return current
|
||||||
|
# !SECTION Players selection menu
|
||||||
|
|
||||||
|
# SECTION Character display list
|
||||||
|
def display_characters(current_player, to_choose=False):
|
||||||
|
print("\nAvailable characters:")
|
||||||
|
counter = 0
|
||||||
|
for character in current_player.characters:
|
||||||
|
counter += 1
|
||||||
|
print(str(counter) + ": " + character.name)
|
||||||
|
print("\n===============================================\n")
|
||||||
|
if to_choose:
|
||||||
|
valid = False
|
||||||
|
while not valid:
|
||||||
|
choice = input("Select a character: ")
|
||||||
|
if choice.isdigit():
|
||||||
|
if choice <= len(current_player.characters):
|
||||||
|
choice = int(choice)
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
print("Invalid choice!")
|
||||||
|
else:
|
||||||
|
print("Invalid choice!")
|
||||||
|
return current_player.characters[choice - 1]
|
||||||
|
# !SECTION Character display list
|
||||||
|
|
||||||
|
# !SECTION Debug methods
|
||||||
|
|
||||||
|
# SECTION Helper methods
|
||||||
|
def search_fight():
|
||||||
|
# TODO network game search
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def load_fight(match_id):
|
||||||
|
fight = game.init_fight(match_id)
|
||||||
|
# TODO
|
||||||
|
# !SECTION Helper methods
|
||||||
|
|
||||||
|
# SECTION Main routine
|
||||||
|
|
||||||
|
# ANCHOR Global variables
|
||||||
|
game = None
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
game = gamelib.cfo.Game()
|
||||||
|
# NOTE Creating a new player or loading an existing one
|
||||||
|
if len(game.players) == 0:
|
||||||
|
username = input("Chose an username: ")
|
||||||
|
game.new_player(username)
|
||||||
|
# NOTE Saving the players
|
||||||
|
with open("players.pickle", "wb") as f:
|
||||||
|
pickle.dump(game.players, f)
|
||||||
|
|
||||||
|
# ANCHOR Debug CLI game instance
|
||||||
|
# NOTE This is a debug CLI game instance
|
||||||
|
# NOTE Presenting the user with the main menu
|
||||||
|
print("Welcome to the CLI game instance")
|
||||||
|
print("|===============================================|")
|
||||||
|
print("|=============== Code Of Honor =================|")
|
||||||
|
print("|=============== Streamline =================|")
|
||||||
|
print("|===============================================|")
|
||||||
|
game.current_player = player_menu(game.players)
|
||||||
|
display_characters(game.current_player)
|
||||||
|
|
||||||
|
# SECTION Choice menu
|
||||||
|
print("1) Load a character")
|
||||||
|
print("2) Find a fight")
|
||||||
|
print("3) Logout")
|
||||||
|
print("4) Exit")
|
||||||
|
valid = False
|
||||||
|
# NOTE Choice loop
|
||||||
|
while not exiting:
|
||||||
|
exiting = True
|
||||||
|
choice = input("-\nChoose what to do: ")
|
||||||
|
if (choice == "1"):
|
||||||
|
print("Loading a character")
|
||||||
|
game.loaded_character = display_characters(
|
||||||
|
game.current_player, True)
|
||||||
|
exiting = False
|
||||||
|
elif (choice == "2"):
|
||||||
|
print("Finding a fight")
|
||||||
|
# NOTE Start the server and look for avail
|
||||||
|
# servers abroad
|
||||||
|
# TODO match_id determination
|
||||||
|
fight = game.init_fight(0)
|
||||||
|
game.start_socket()
|
||||||
|
# NOTE Here starts the whole while loop managed by
|
||||||
|
# listen_to_socket()
|
||||||
|
success, end_result, message = game.listen_to_socket()
|
||||||
|
if success:
|
||||||
|
if end_result:
|
||||||
|
print("You won the fight!")
|
||||||
|
else:
|
||||||
|
print("You lost the fight!")
|
||||||
|
else:
|
||||||
|
print("ERROR: " + message)
|
||||||
|
exiting = False
|
||||||
|
elif (choice == "3"):
|
||||||
|
print("Logging out")
|
||||||
|
game.current_player = None
|
||||||
|
player_menu(game.players)
|
||||||
|
# Returning to the menu
|
||||||
|
exiting = False
|
||||||
|
elif (choice == "4"):
|
||||||
|
print("Exiting")
|
||||||
|
os._exit(0)
|
||||||
|
else:
|
||||||
|
print("Invalid choice!")
|
||||||
|
exiting = False
|
||||||
|
# !SECTION Choice menu
|
||||||
|
|
||||||
|
# !SECTION Main routine
|
Loading…
x
Reference in New Issue
Block a user