So far I have split the engine in two pieces: the initial set up and the actual engine itself.
The set up is:
Code: Select all
init python:
#define a player object
# Stat Shorthand List:
# exp = Current Experience
# Level = Current Level
# HP = Current Health Points
# MHP = Max Hit Points
# CP = Current Code Points
# MCP = Max Code Points
# STR = Base Strength
# VIT = Base Vitality
# INT = Base Intelligence
# SPD = Base Speed
# DEF = Base Defense
## Maximum level is 99
## Maximum stat is 255
maxlevel = 99
maxstat = 255
# All abilities and moves is organized as Ability Codes.
# Only Player can change it out.
# All other characters have fixed ability codes
#creates empty character, moster, and boss lists
character_list = {}
monster_list = {}
boss_list = {}
encounter_list = {}
battle_bkg_list = {}
weapon_list = {}
armor_list = {}
### Classes
class battle_bkg:
def __init__(self, name, image, location):
self.name = name
self.image = image
self.location = location
class player:
def __init__(self, name, exp, level, strength, vitality, intelligence, speed, hp, mhp, cp, mcp, attack, defense, weapon, armor, ac1, ac2, ac3, ac4, ac5, buff, debuff, status, defend=False):
self.name = name
self.exp = exp
self.level = level
self.strength = strength
self.vitality = vitality
self.intelligence = intelligence
self.speed = speed
self.hp = hp
self.mhp = mhp
self.cp = cp
self.mcp = mcp
self.attack = attack
self.defense = defense
self.weapon = weapon
self.armor = armor
self.ac1 = ac1
self.ac2 = ac2
self.ac3 = ac3
self.ac4 = ac4
self.ac5 = ac5
self.buff = buff
self.debuff = debuff
self.status = status
self.defend = defend
## add defend function here
#define a monster object
class monster:
def __init__(self, name, image, level, strength, vitality, intelligence, speed, hp, mhp, attack, defense, mac1, mac2, mac3, mac4, mac5, buff, debuff, status, weak, gp, exp, item01, item02, item03):
self.name = name
self.image = image
self.level = level
self.strength = strength
self.vitality = vitality
self.intelligence = intelligence
self.speed = speed
self.hp = hp
self.mhp = mhp
self.attack = attack
self.defense = defense
self.mac1 = mac1
self.mac2 = mac2
self.mac3 = mac3
self.mac4 = mac4
self.mac5 = mac5
self.buff = buff
self.debuff = debuff
self.status = status
self.weak = weak
self.gp = gp
self.exp = exp
self.item01 = item01
self.item02 = item02
self.item03 = item03
class encounter:
def __init__(self, groupname, size, enemy1, enemy2, enemy3, enemy4, location):
self.groupname = groupname
self.size = size
self.enemy1 = enemy1
self.enemy2 = enemy2
self.enemy3 = enemy3
self.enemy4 = enemy4
self.location = location
class weapon:
def __init__(self, name, strength, element, status, modifier):
self.name = name
self.strength = strength
self.element = element
self.status = status
self.modifier = modifier #additional adjustment to stat
class armor:
def __init__(self, name, defense, element, status, modifier):
self.name = name
self.strength = strength
self.element = element
self.status = status #note: this blocks status
self.modifier = modifier #additional adjustment to stat
## Database for Weapons
##
weapon_list["stick"] = weapon("Stick", 5, "none", "none", "none")
## Database for Armors
## Database for Weapons
##
armor_list["clothes"] =armor("Clothes", 1, "none", "none", "none")
## Database for Characters
##
character_list["player"] = player("[playername]", 0, 1, 5, 3, 3, 4, 30, 30, 10, 10, 5, 4, weapon_list["stick"], armor_list["clothes"], [], [], [], [], [], "none", "none", "none")
#
#
#
#
#
#
#
#
#
#
#
#
#Set up Current Party List (Limit is 4), Defaults to just player
party_list = [character_list["player"]]
#Set Up Reserve Party (Defaults to empty until later addition)
#reserve_party = [ ]
## Database for Monsters
##
monster_list["direspider"] = monster("Dire Spider", "monster_direspider", 2, 5, 3, 0, 1, 25, 25, 10, 4, [], [], [], [], [], "none", "none", "none", "fire", 10, 10, "herb", "none", "none" )
## Database for Boss
##
#boss_list["icy"] = monster( )
## Set up Default Encounter Groups
encounter_list["shartwospiders"] = encounter("shartwospiders", 2, monster_list["direspider"], monster_list["direspider"], "none", "none", "sharforest")
## Set up Boss Encounters
#encounter_list["bossicy"] = encounter("bossicy", boss_list["icy"], "none", "none", "none", "greenshirehills")
## Database for backgrounds
battle_bkg_list["sharforest"] = battle_bkg("Shar Forest", "battle_sharforest", "sharforest")
battle_bkg_list["greenshirehillsnight"]= battle_bkg("Greenshire Hills at Night", "battle_greenshirehills_night", "greenshirehills")
Code: Select all
### Battle Screens
##sets up battle background
screen battle_background(location):
zorder 0
add battle_bkg_list[location].image
##sets up battle message window
screen battle_message(message):
zorder 6
frame:
xalign 0.5
xfill True
yalign 0.0
ysize 60
text message
##battle HUD
screen battle_HUD:
zorder 5
grid 4 1:
$ null_members = 4 - len(party_list)
xalign 0.5
yalign 0.98
for member in party_list:
frame:
vbox:
xsize 240
ysize 80
spacing 10
text member.name
hbox:
spacing 10
bar value member.hp range member.mhp
text _("HP")
hbox:
spacing 10
bar value member.cp range member.mcp
text _("CP")
#add member.status
for count in range(null_members):
null
##Enemy Display Area
screen battle_enemy(encounter):
zorder 1
$ group_size = encounter_list[encounter].size
if group_size == 1:
grid 1 1:
xfill True
yfill True
add encounter_list[encounter].enemy1.image at battle_monsterSpawn(encounter_list[encounter].enemy1.image)
elif group_size == 2:
grid 2 1:
xfill True
yfill True
xalign 0.5
yalign 0.5
add encounter_list[encounter].enemy1.image at battle_monsterSpawn(encounter_list[encounter].enemy1.image)
add encounter_list[encounter].enemy2.image at battle_monsterSpawn(encounter_list[encounter].enemy2.image)
elif group_size == 3:
grid 3 1:
xfill True
yfill True
add encounter_list[encounter].enemy1.image at battle_monsterSpawn(encounter_list[encounter].enemy1.image)
add encounter_list[encounter].enemy2.image at battle_monsterSpawn(encounter_list[encounter].enemy2.image)
add encounter_list[encounter].enemy3.image at battle_monsterSpawn(encounter_list[encounter].enemy3.image)
else:
grid 4 1:
xfill True
yfill True
add encounter_list[encounter].enemy1.image at battle_monsterSpawn(encounter_list[encounter].enemy1.image)
add encounter_list[encounter].enemy2.image at battle_monsterSpawn(encounter_list[encounter].enemy2.image)
add encounter_list[encounter].enemy3.image at battle_monsterSpawn(encounter_list[encounter].enemy3.image)
add encounter_list[encounter].enemy4.image at battle_monsterSpawn(encounter_list[encounter].enemy4.image)
##battle actions menu
screen battle_actions(character):
zorder 5
hbox:
xalign 0.5
yalign 0.5
textbutton _("Attack"):
action Return("attack")
textbutton _("Ability Codes"):
action Return("ability")
textbutton _("Items"):
action Return("items")
textbutton _("Defend"):
action Return("defend")
##battle skill menu
screen battle_skills(character):
zorder 5
frame:
xalign 0.5
yalign 0.5
for skill in character_list[character]:
if not skill.ac1 == []:
textbutton skill.ac1.name action Return(skill.ac1)
if not skill.ac2 == []:
textbutton skill.ac2.name action Return(skill.ac2)
if not skill.ac3 == []:
textbutton skill.ac3.name action Return(skill.ac3)
if not skill.ac4 == []:
textbutton skill.ac4.name action Return(skill.ac4)
if not skill.ac5 == []:
textbutton skill.ac5.name action Return(skill.ac5)
##battle enemy target menu
screen enemy_target(encounter):
zorder 5
hbox:
xalign 0.5
yalign 0.5
$ group_size = encounter_list[encounter].size
textbutton encounter_list[encounter].enemy1.name action Return(".enemy1")
if group_size > 1:
textbutton encounter_list[encounter].enemy2.name action Return(".enemy2")
if group_size > 2:
textbutton encounter_list[encounter].enemy3.name action Return(".enemy3")
if group_size > 3:
textbutton encounter_list[encounter].enemy4.name action Return(".enemy4")
##battle party target menu
screen party_target:
pass
##battle battle items
screen battle_items:
pass
### Battle Logic System:
### write a label to call when battle is triggered.
## passes background image, party list, enemy lists
## returns battle conditions
init python:
def battle(location, monsterparty):
#displays background
renpy.show_screen("battle_background",location)
#show HUD
renpy.show_screen("battle_enemy",monsterparty)
renpy.show_screen("battle_HUD")
victory = False
renpy.pause(1, hard="true")
target = []
loop = 1 #keep looping
while loop == 1:
## character actions
for member in party_list:
action = renpy.call_screen("battle_actions", member)
if action == "attack":
## go to enemy attack
target = renpy.call_screen("enemy_target", monsterparty)
#attack enemy
#damage = member.attack - enemytarget.defense
#enemytarget.hp -= damage
#"you have hit [enemytarget] for [damage] points of damage."
elif action == "ability":
skill_load = renpy.call_screen("battle_skills", member)
#target
# use actions
elif action == "items":
item_load = renpy.call_screen("battle_items")
#target
# use item
elif action == "defend":
member.defend = True
## enemy actions
for enemy in monsterparty:
renpy.random.randint(1,len(party_list))
## check victory conditions
## return condition when finished.
return victory
It may be worth keeping the post on the forum so you can have additional input as well. I'm not the best programmer around the forum by any stretch!
I spotted a mistake in your code where you defined the cloth armour and you used weapon() instead of armor().
Also, you're going to run into problems with your monsters if you create them once, put them in a dict and then assign them to encounters. In essence you've created 1 instance of each monster, and then putting them into the encounter multiple times (direspider x 2). What happens is, you'll just have 1 dire spider referenced twice in your encounter - with one health bar. Hit one means you're damaging both.
To get around that, you can make your encounter class generate new instances of monsters on __init__(). I'd in fact pass a list of enemies as strings to the class, and it'll loop through the list, read off the global monster list and reproduce new instances of the monsters:
Pseudo code here (just shows the concept):
Code: Select all
def __init__(self, groupname, enemies, location): # size is just len(enemies)
self.groupname = groupname
self.location = location
self.enemies = []
global monster_list # get a handle on the global monster list
for enemy in enemies:
self.enemies.append(new monster(monster_list[enemy].name, monster_list[enemy].image, monster_list[enemy].level etc. etc.))
# create a size attribute via function
@property
def size(self):
return len(self.enemies)
I was suggested to post all of this to see if others have some ideas to help improve the engine to make it dynamic.our monster and player class also share a lot of similarities, and as such can be done via an extension to simplify your code. I'll let you read up on that yourself though as it's not that fundamental.
I've only glance read your screen codes and saw that you have an if statement by the size of the encounter - there's a lot of code redundancy there - it should be handled by a for loop to add all enemy images. Your grid is basically grid encounter_list[encounter].size 1, not sure why you only have xalign yalign 0.5 for group size 2, but you can definitely for loop through the enemy list.
In terms of abilities, you should have a dictionary to keep all the abilities, then you can add them to the player / characters / monsters easily.
I don't see an ability class though, which will be useful - it should contain things like modifiers, status effects, and depending on how flexible your battle system is - possible targets etc. It should also have an execute function that takes in the caster (so you can subtract MP for example), the targets (depending on whether you allow abilities to be casted on multiple targets.
Now you should have additional functions that performs different type of abilities - offensive, defensive, buffs, debuffs etc. - depending on what your battle system can do. And your execute function will perform the appropriate function depending on what kind of ability it is (stored as an attribute on creation), then you can perform different types of calculations: offensive takes defence stats, but restorative abilities can ignore them, and do the suitable modifications to your targets.
You should probably also have a function that takes in the party and encounter and returns possible targets - depending on how flexible or rigid your battle system is.
It's quite a lot of work if I'm honest, especially when you have multiple combatants in your battles, but it's definitely achievable.