Developing a RPG Engine for Renpy

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Message
Author
User avatar
hyperionthunder
Regular
Posts: 51
Joined: Fri May 18, 2018 2:10 pm
Projects: The Wanderers
Deviantart: hyperionthunder
itch: hyperionthunder
Contact:

Developing a RPG Engine for Renpy

#1 Post by hyperionthunder »

Hello, I am writing an engine that I plan to place within my VN project. I intend to have the engine function as a secondary focus of the game.

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")
    
And the screen language and logic:

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
 
I have recieved feedback from KIVIK on what to look for and here was his suggestions:
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)
 
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.
I was suggested to post all of this to see if others have some ideas to help improve the engine to make it dynamic.

User avatar
hyperionthunder
Regular
Posts: 51
Joined: Fri May 18, 2018 2:10 pm
Projects: The Wanderers
Deviantart: hyperionthunder
itch: hyperionthunder
Contact:

Re: Developing a RPG Engine for Renpy

#2 Post by hyperionthunder »

Here is the change based on suggestions:
For the encounter class:

Code: Select all

class encounter:
        def __init__(self, groupname, enemies, location):
            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(monster(monster_list[enemy].name,
                    monster_list[enemy].image,
                    monster_list[enemy].level,
                    monster_list[enemy].strength,
                    monster_list[enemy].vitality,
                    monster_list[enemy].intelligence,
                    monster_list[enemy].speed,
                    monster_list[enemy].hp,
                    monster_list[enemy].mhp,
                    monster_list[enemy].attack,
                    monster_list[enemy].defense,
                    monster_list[enemy].mac1,
                    monster_list[enemy].mac2,
                    monster_list[enemy].mac3,
                    monster_list[enemy].mac4,
                    monster_list[enemy].mac5,
                    monster_list[enemy].buff,
                    monster_list[enemy].debuff,
                    monster_list[enemy].status,
                    monster_list[enemy].weak,
                    monster_list[enemy].gp,
                    monster_list[enemy].exp,
                    monster_list[enemy].item1,
                    monster_list[enemy].item2,
                    monster_list[enemy].item3))
                    
            # create a size attribute via function
            @property
            def size(self):
                return len(self.enemies)
and the encounter_list is

Code: Select all

encounter_list["shartwospiders"] = encounter("shartwospiders", ["direspider", "direspider"], "sharforest")
when i try to use the following code to create a sprite on the screen with a grid:

Code: Select all

grid encounter_list[encounter].size 1:
        xfill True
        yfill True
        for enemy in encounter_list[encounter].enemies:
            add enemy.image at battle_monsterSpawn(enemy.image)
it gave me an error:
While running game code:
File "game/battle_setup.rpy", line 1, in script
init python:
File "game/battle_setup.rpy", line 214, in <module>
encounter_list["shartwospiders"] = encounter("shartwospiders", ["direspider", "direspider"], "sharforest")
File "game/battle_setup.rpy", line 106, in __init__
self.size()
AttributeError: 'encounter' object has no attribute 'size'
I looked at the code and think they are correct.... maybe.

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Developing a RPG Engine for Renpy

#3 Post by Remix »

@property is inside __init__ ... de-indent by one tab
Also (as Ren'py is pre Python 3) use class ClassName( object_it_extends ) e.g. class Encounter(object): to ensure you expose methods of the object class.

Personally I would sub, sub and sub-class again to create instances... It gets pretty complex to make sure you are pulling attributes from the right object though.
Might run up a basic overview later or tomorrow
Frameworks & Scriptlets:

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Developing a RPG Engine for Renpy

#4 Post by kivik »

Oops, sorry for missing the indentation for the @property function when I wrote it!

User avatar
hyperionthunder
Regular
Posts: 51
Joined: Fri May 18, 2018 2:10 pm
Projects: The Wanderers
Deviantart: hyperionthunder
itch: hyperionthunder
Contact:

Re: Developing a RPG Engine for Renpy

#5 Post by hyperionthunder »

Ok i got some things working but the next step i am stuck at is figuring out how to dynamically target a monster

in the battle actions for the player after picking attack (single target)

Code: Select all

battle_target = renpy.call_screen("enemy_target", monsterparty)
then it goes to

Code: Select all

screen enemy_target(encounter):
    zorder 5
    frame:
        xalign 0.5
        yalign 0.5
        vbox:
            spacing 10
            for enemy in encounter_list[encounter].enemies:
                textbutton enemy.name action If(enemy in battle_target, RemoveFromSet(battle_target, enemy), AddToSet(battle_target, enemy))
but i am kind of stuck at how to pass the pointer of that enemy into the target to use as a way of manipulating an enemy inside the encounter list.

I thought about doing an object target that copies the target enemy over, to pass information between encounter_list and target variable

Code: Select all

class target:
        def __init__(self, name, hp, mhp, defense, status, buff, debuff):
            self.name = name
            self.hp = hp
            self.mhp = mhp
            self.defense = defense
            self.status = status
            self.buff = buff
            self.debuff = debuff

            global encounter_list
i had this as a global variable to hold the chosen enemy's data

Code: Select all

            
    battle_target = []

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Developing a RPG Engine for Renpy

#6 Post by kivik »

Since you're holding an instance of a monster inside your encounter list, when you add the monster (in your AddToSet(battle_target, enemy)) to the battle_target list, you're actually add the pointer to the battle_target. That means if you manipulate the monster inside the battle_target list now, you'll be manipulating the actual monster the player selected.

This was why I suggested you create copies of the monsters for your encounter in the first place, or in encounters where you have multiple of the same monster - a single instance of the monster would be affected by all actions towards any of them (as they'd all share the same pointer). You don't have that problem anymore, so just do what you want with the monster now.

A way to visualise this:

monster1_pointer = Monster(10/10 hp)
monster2_pointer = Monster(20/20 hp)
monster3_pointer = Monster(30/30 hp)

Encounter Object:
self.enemies = [monster1_pointer, monster2_pointer, monster3_pointer]

after you add monster2_pointer to battle_target:

battle_target[monster2_pointer]

Now if you attack what's inside battle_target and deal 10 damage:

monster2_pointer = Monster(10/20 hp)

And if you look at your Encounter Object's monster2 now, it'll have 10hp left.


Hope that helps?

User avatar
hyperionthunder
Regular
Posts: 51
Joined: Fri May 18, 2018 2:10 pm
Projects: The Wanderers
Deviantart: hyperionthunder
itch: hyperionthunder
Contact:

Re: Developing a RPG Engine for Renpy

#7 Post by hyperionthunder »

That's what i was thinking. The issue is how do reference that pointer inside the battle_target variable?
do i do it like battle_target.name, for name, since the loaded enemy has the property taken from a monster class...

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Developing a RPG Engine for Renpy

#8 Post by kivik »

Well battle_target is a list, so you'd have to iterate over the list with a for loop and then reference the enemy's name individually.

Out of curiosity, did you mean to make a list of enemies or should it function as a single enemy?

User avatar
hyperionthunder
Regular
Posts: 51
Joined: Fri May 18, 2018 2:10 pm
Projects: The Wanderers
Deviantart: hyperionthunder
itch: hyperionthunder
Contact:

Re: Developing a RPG Engine for Renpy

#9 Post by hyperionthunder »

I want the target to function on a single enemy.

currently i have it configured to do:

Code: Select all

## go to target enemy for single attack
renpy.call_screen("enemy_target", monsterparty)

damage  = member.attack - battle_target.defense # + modifiers

battle_target.hp -= damage

renpy.say(None, "you have hit [battle_target.name] for [damage] points of damage.")

and I had the enemy target function set up as:

Code: Select all


screen enemy_target(encounter):
    zorder 5
    frame:
        xalign 0.5
        yalign 0.5
        vbox:
            spacing 10
            for enemy in encounter_list[encounter].enemies:
                textbutton enemy.name:
                    action [If(enemy in battle_target, RemoveFromSet(battle_target, enemy), AddToSet(battle_target, enemy)), Hide("enemy_target"), Return()]


kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Developing a RPG Engine for Renpy

#10 Post by kivik »

If you're doing a single targets, don't use AddToSet() and RemoveFromSet(), use SetVariable() instead, then you'll be able to do battle_target.hp -= damage.

User avatar
hyperionthunder
Regular
Posts: 51
Joined: Fri May 18, 2018 2:10 pm
Projects: The Wanderers
Deviantart: hyperionthunder
itch: hyperionthunder
Contact:

Re: Developing a RPG Engine for Renpy

#11 Post by hyperionthunder »

That did the trick. The targeting works perfectly.

now i have a different error when I try to display the current player's name during his turn. In the code I have written

Code: Select all

for member in party_list:
                renpy.show_screen("battle_message","[member.name]'s Turn.")
                action = renpy.call_screen("battle_actions", member)

                if action == "attack":
....

and the code for the screen is

Code: Select all

screen battle_message(message):
    zorder 5
    frame:
        xsize 1000
        ysize 80
        xalign 0.5
        yalign 0.0
        text message xalign 0.5 yalign 0.5
it results in this error:
I'm sorry, but an uncaught exception occurred.

While running game code:
File "game/script-chapter-02-day-06.rpy", line 49, in script
$ condition = battle("sharforest","shartwospiders")
File "game/script-chapter-02-day-06.rpy", line 49, in <module>
$ condition = battle("sharforest","shartwospiders")
File "game/battle.rpy", line 160, in battle
damage = 2 * (member.attack - battle_target.defense)
File "game/battle.rpy", line 121, in execute
screen battle_message(message):
File "game/battle.rpy", line 121, in execute
screen battle_message(message):
File "game/battle.rpy", line 123, in execute
frame:
File "game/battle.rpy", line 128, in execute
text message xalign 0.5 yalign 0.5
NameError: Name 'member' is not defined.

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Developing a RPG Engine for Renpy

#12 Post by kivik »

Don't mix scoped variables (in for member in party_list:, the variable member only exists for the duration of the for loop) with Renpy's text interpolation ("[variable]". What's happening is, you're passing "[member]" to a screen, but the screen doesn't have access to member within your for loop.

If you want to add a variable to a string to be used, you need to use string operators to add it in:

Code: Select all

renpy.show_screen("battle_message","%s's Turn." % member.name)
Here: "%s" % variable_name substitutes the %s with what's inside variable_name. You can read more about it here: http://www.diveintopython.net/native_da ... rings.html

User avatar
hyperionthunder
Regular
Posts: 51
Joined: Fri May 18, 2018 2:10 pm
Projects: The Wanderers
Deviantart: hyperionthunder
itch: hyperionthunder
Contact:

Re: Developing a RPG Engine for Renpy

#13 Post by hyperionthunder »

Ah that's why!

User avatar
hyperionthunder
Regular
Posts: 51
Joined: Fri May 18, 2018 2:10 pm
Projects: The Wanderers
Deviantart: hyperionthunder
itch: hyperionthunder
Contact:

Re: Developing a RPG Engine for Renpy

#14 Post by hyperionthunder »

I am working on the dynamic of the stat creation and math. I think I kind of figured it out but I wanted to ask others for opinion on what's the best kind of RPG formula for like HP and base stat. I am using Strength for Attack, Vit for HP and Defense, Int for MP and Spell Damage / Heals, and SPD for speed and evasion.

I feel like i am slowly sinking into the hell hole of making the game more complex than I had originally thought. ^^u :lol:

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Developing a RPG Engine for Renpy

#15 Post by kivik »

Worth asking at the Creator Discussion forum. I'd suggest you actually just take an existing game's formulas and use that - including the level up scaling. The reason being it's a fine art to balance stats especially when you scale up your characters' stats and keep the game fair (not overly easy or difficult).

Damage mitigation alone (based on defense) is a very complicated thing. Have you factored in things like armours and weapons? What about spell defense? If you do spell defense you need to make sure healing isn't affected badly (healing effect being mitigated).

Good luck!

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot]