Dungeon Crawl RPG Framework

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
Message
Author
User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: Dungeon crawling RPG frame

#46 Post by nyaatrap » Mon Apr 22, 2013 9:12 pm

$player.skills.remove(x). There are many python built-in you google with "python list".

Field values and store.variables (you need to add "store." for normal variables when changing them in python methods) should be recorded anywhere unless they are properly initialized after "start" game (That means, initialize them on the top of the start label).

DapNix
Regular
Posts: 52
Joined: Fri Mar 01, 2013 6:15 am
Contact:

Re: Dungeon crawling RPG frame

#47 Post by DapNix » Tue Apr 23, 2013 9:41 am

It's not going very well. I'll show my involved code:

Code: Select all

label start:
    #Add Skills (Name, Hitrate, Power)
    $ Slash = Skill("Slash", 100, 8)
    $ Wait = Skill("Wait", 100, 0)
    $ Stare = Skill("Stare", 100, 3)
    $ Decapitation = Skill("Decapitation", 100, 71)

    #Add battle characters (Name, Stats, Skills)
    $ player = Actor("Algan", 1, 5, 5, 5, 5, 125, [Slash, Wait])
    $ enemy = Actor("Lesser Demon", 1, 3, 3, 3, 3, 95, [Stare])
I have the characters and their stats.

Code: Select all

    class Actor(renpy.store.object):
        def __init__(self, name, lvl, str, dex, int, end, max_hp, skills=[]):
            self.name=name
            self.str = str
            self.dex = dex
            self.int = int
            self.end = end
            self.lvl = lvl
            self.max_hp = 50+end*15
            self.hp = max_hp
            self.skills = skills

        def levelup(self):
            self.lvl += 1
            self.str += 1
            self.dex += 1
            self.int += 1
            self.end += 1
There are my stats informations.

Code: Select all

label afterbattle:
$ player.levelup()
""
And if the battle is won this is what you get. The stats go up, yet the hp won't follow the formula. Since I've added in the stats informations in instances, can I really save it as variables?

User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: Dungeon crawling RPG frame

#48 Post by nyaatrap » Tue Apr 23, 2013 12:24 pm

You diden' put:

Code: Select all

def levelup(self):
    self.max_hp += 15

DapNix
Regular
Posts: 52
Joined: Fri Mar 01, 2013 6:15 am
Contact:

Re: Dungeon crawling RPG frame

#49 Post by DapNix » Tue Apr 23, 2013 2:42 pm

nyaatrap wrote:You diden' put:

Code: Select all

def levelup(self):
    self.max_hp += 15
But I'm using a formula for hp, which is, as in the code, max_hp = 50+end*15
Therefore, I should have a base HP of 50, and every point of endurance should give me 15 more HP.
I will also later add that str will boost damage. Therefore I need the stats to do changes to the game.
Or do I have to up the hp like that? If I have to, will the str, int and dex do any difference then?

User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: Dungeon crawling RPG frame

#50 Post by nyaatrap » Tue Apr 23, 2013 8:02 pm

__init__ is a simple method which is only called when creating instances. It actually means:

Code: Select all

instance=Class
instance.__init__(instance,arg1,arg2)
There is no special magic like modifying other methods called later in this method.

clannadman

Re: Dungeon crawling RPG frame

#51 Post by clannadman » Thu Jun 27, 2013 12:05 pm

Hi. I'm having issues with my attack/command sequence. I'm not sure what's causing it, but the skills buttons fail to appear during battle, even after the code was reverted back to what it was previously. Here's what I currently have:

Code: Select all

init:
    # Screen used for selecting skills
    screen command:   
        vbox align (.5,.5):
            for i in player.skills:
                textbutton "[i.name]" action Return (value=i)

    # Screen which shows battle status
    screen battle_ui:    
        use battle_frame(char=player, position=(.95,.05))
        use battle_frame(char=enemy, position=(.05,.05))
        
    screen battle_frame:
        frame area (0, 0, 250, 80) align position:
            vbox yfill True:
                text "[char.name]"
                hbox xfill True:
                    text "HP"
                    text "[char.hp]/[char.max_hp]" xalign 1.0

                    
init python:    
   

    # Create skills (name, hit, power, type)
    Shoot = Skill("Shoot", 100, 20, "attack", "shoot image", .3)
    Grenade = Skill("Grenade", 100, 40, "attack", "grenade image", .3)
    Artillery = Skill("Artillery", 30, 100, "attack", "artillery image", .3)
    Drive = Skill("Drive", 50, 50, "attack", "drive image", .3)
    Heal = Skill("Heal", 0, 100, "heal", "heal image", .3)
    
    #Boss powers
    ZhukovShoot = Skill("Flame Fist", 100, 50, "attack", "zhukov shoot image", .3)
    ZhukovFire = Skill("Zhukov Fire", 80, 80, "attack", "zhukov fire image", .3)
    ZhukovInferno = Skill("Zhukov Inferno", 80, 100, "attack", "zhukov inferno image", .3)
    PowerofLenin = Skill("Power of Lenin", 90, 500, "attack", "zhukov lenin image", .3)
    
    # Create battle actors (name, max_hp, skills)
    player = Actor("Yamato Unit",0, 0,[Shoot, Grenade, Heal])
    czechi = Actor("Czech Infantry",80, 1, [Shoot, Grenade])
    poli = Actor("Polish Infantry",80, 2, [Shoot, Grenade])
    polt = Actor("Polish Tank Crew",100, 3, [Artillery, Drive])
    zhuko = Actor("Zhukov",5000, 50, [ZhukovShoot, ZhukovFire, ZhukovInferno, PowerofLenin])

    

init -1 python:
    # Import the copy module for copying instanses.
    from copy import copy
    
    # Class used for battle skills
    class Skill():
        def __init__(self, name, hit, power, type, image, wait):
            self.name = name
            self.hit = hit
            self.power = power  
            self.type = type
            self.image = image
            self.wait = wait
            
    # Class used for battle characters. Inherit renpy.store.object for the rollback function.
    class Actor(renpy.store.object):
        def __init__(self, name, max_hp=0, level=0, skills=[]):
            self.name=name
            self.max_hp=max_hp
            self.hp=max_hp
            self.level=level
            self.skills = skills
            
            
        def command(self, target):
            self.skill = renpy.call_screen("command")
            if self.skill.type=="attack":
                self.attack(self.skill, target)
            elif self.skill.type=="heal":
                self.heal(self.skill)
            
            target.skill = renpy.random.choice(target.skills)  
            if target.hp < 1:
                return
            target.attack(target.skill, self)
            
            
        def attack(self,skill,target):
            renpy.show(self.skill.image)
            renpy.pause(self.skill.wait,hard=True)
            if self.skill.type=="attack":
                self.attack(self.skill, target)
                if self.skill.hit<renpy.random.randint (0,100):
                    narrator ("{} used {}. {} narrowly dodged {}'s attack.".format(self.name, self.skill.name, target.name, self.name))
                else:
                    target.hp -= self.skill.power
                    narrator ("{} used {}. {} received {} damage.".format(self.name, self.skill.name, target.name, self.skill.power))
            elif self.skill.type=="heal":
                self.heal(self.skill) 

         
                
            renpy.hide(self.skill.image) #Usually, hide is needed to work the next animation correctly
            
        def reset(self, target):
            self.hp = self.max_hp
            target.hp = target.max_hp          
    
        def heal(self, skill):
            self.hp += self.skill.power
            # ("{} used {}. {} recovered {}HP".format(self.name, self.skill.name, self.name, self.skill.power))
            #renpy.hide(self.skill.image) #Usually, hide is needed to work the next animation correctly
            #renpy.call_screen("command")
            
        def levelup(self):
            self.level += 1
            self.hp += 100

            
label battle:
    $ player = Actor("Yamato Unit", max_hp=100, level=1)
    $ config.rollback_enabled=False
    $ enemy=zhuko
    show screen battle_ui

    "[enemy.name] wants to battle!"

    show screen command
    while enemy.hp>0:
        $ player.command(enemy)
        if player.hp <1:
            
            me "Gah! Such power..."
            stop music fadeout 2.0
            hide screen battle_ui
            jump zhukovloss
            
    me "I won?"
    "I don't know how I did it but I won."
    "At that moment, a light emanates from Zhukov's body."
    "Within seconds, I'm sent hurtling through the air."
    me "Gah! I lost?"
    stop music fadeout 2.0
    hide screen battle_ui
    jump zhukovloss

label zhukovloss:
    play sound "se/loss.wav"
    $ player.reset(enemy) 
    
    "Yamato lost the battle."                              
    
    $ config.rollback_enabled=True
It happened with another battle, so I deleted that and tried again. It was working but now the command screen just won't appear. I was also trying to get the attack and heal narration working separately. So it would actually take you to the def heal as opposed to the def attack. However, it seems to loop back to def attack so you got two lots of narration i.e. 'Yamato used Heal. Zhukov narrowly dodged the attack', followed by another such statement. So it was a double-hit, happening twice but also constantly linking back to def attack rather than simply going to def heal before the enemy made their attack.

Now, once again, the command buttons just aren't showing. Help?

Ryue
Miko-Class Veteran
Posts: 745
Joined: Fri Nov 02, 2012 8:41 am
Projects: Red eyes in the darkness
Contact:

Re: Dungeon crawling RPG frame

#52 Post by Ryue » Fri Jun 28, 2013 3:02 am

I think i have found something.

Direcctly under label start:
$ player = Actor("Yamato Unit", max_hp=100, level=1)

with that you are overwriting the player variable you set at init (the one at init has the skills, the one under start has no skills thus no buttons will be shown).


On that note also:
Don't initialize/set variables that can change (like player,...) in an init part. I have had a few talks there and it can cause havoc when you save and load.

clannadman

Re: Dungeon crawling RPG frame

#53 Post by clannadman » Fri Jun 28, 2013 12:39 pm

Wolf wrote:I think i have found something.

Direcctly under label start:
$ player = Actor("Yamato Unit", max_hp=100, level=1)

with that you are overwriting the player variable you set at init (the one at init has the skills, the one under start has no skills thus no buttons will be shown).


On that note also:
Don't initialize/set variables that can change (like player,...) in an init part. I have had a few talks there and it can cause havoc when you save and load.
Thank you. That's sorted the button issue. Although trying to set the player variable under label start is causing issues. When trying to add skills in the same manner using [], I get an arg complaint:

Code: Select all

    $ player = Actor("Yamato Unit", max_hp=100, [Shoot, Grenade, Heal])

File "game/script.rpy", line 680: non-keyword arg after keyword arg

User avatar
Anima
Veteran
Posts: 448
Joined: Wed Nov 18, 2009 11:17 am
Completed: Loren
Projects: PS2
Location: Germany
Contact:

Re: Dungeon crawling RPG frame

#54 Post by Anima » Fri Jun 28, 2013 1:08 pm

The problem is that keyword arguments (everything in the form eggs=spam) must come after arguments that are assigned by position.

Code: Select all

$ player = Actor("Yamato Unit", max_hp=100, skills=[Shoot, Grenade, Heal])
should work.
Avatar created with this deviation by Crysa
Currently working on:
  • Winterwolves "Planet Stronghold 2" - RPG Framework: Phase III

clannadman

Re: Dungeon crawling RPG frame

#55 Post by clannadman » Sat Jun 29, 2013 12:22 pm

Anima wrote:The problem is that keyword arguments (everything in the form eggs=spam) must come after arguments that are assigned by position.

Code: Select all

$ player = Actor("Yamato Unit", max_hp=100, skills=[Shoot, Grenade, Heal])
should work.
Thank you, that's worked.

I also worked out a way to make the narrator dialogue work separately for Heal and Attack. Although in order to make certain that Heal doesn't exceed the max_hp (for instance, reaching 140/100 instead of 100/100) I've included this:

Code: Select all

def heal(self, skill):
            if self.skill.power > self.max_hp - self.hp:
                self.hp=self.max_hp
                narrator ("{} used {}.".format(self.name, self.skill.name))
                renpy.play(self.skill.sound)
                narrator ("{} recovered to full health.".format(self.name))
            else:
                self.hp += self.skill.power
                narrator ("{} used {}.".format(self.name, self.skill.name))
                renpy.play(self.skill.sound)
                narrator ("{} recovered {}HP.".format(self.name, self.skill.power))
Although it doesn't seem to work if I give an enemy the option to heal themselves. For some reason it views Heal as an attack to be used, so it'll state something like 'Enemy used Heal. Yamato dodged the attack'. I think it's to do with target.attack(target.skill, self). How would I write this so that it includes the Heal function for enemies but with the correct narration?

Code: Select all

def command(self, target):
            self.skill = renpy.call_screen("command")
            if self.skill.type=="attack":
                self.attack(self.skill, target)
            elif self.skill.type=="heal":
                self.heal(self.skill)
            
            target.skill = renpy.random.choice(target.skills)  
            if target.hp < 1:
                return
            target.attack(target.skill, self)

Ryue
Miko-Class Veteran
Posts: 745
Joined: Fri Nov 02, 2012 8:41 am
Projects: Red eyes in the darkness
Contact:

Re: Dungeon crawling RPG frame

#56 Post by Ryue » Tue Jul 02, 2013 10:31 am

The problem is "this": target.attack(target.skill, self) as you "always" attack.

In effect you would need to do the following instead of target.attack(target.skill, self):

Code: Select all

            if target.skill.type=="attack":
                target.attack(target.skill, target)
            elif target.skill.type=="heal":
                target.heal(target.skill)
If you reconstructure the method you can easy it up so that you only need to write this whole thing only once, but else if we take the current layout you need to "copy"
all skill differentations you make for the players actions also for the mobs actions.

User avatar
sapiboonggames
Veteran
Posts: 291
Joined: Thu Jan 05, 2012 8:53 am
Completed: I Love You, Brother [BxB]
Contact:

Re: Dungeon crawling RPG frame

#57 Post by sapiboonggames » Tue Jul 02, 2013 11:56 am

I love this framework! It's simple yet effective!

I have some questions, though:
1. Is it possible to make the skill conditional with a variable? The skill is only available to use for certain enemies?

2. Also, is it possible to trigger dialogues before battle? (but the dialogues are only for particular enemies)
Visit my website: http://www.sapiboong.com

User avatar
Dragonstar89
Regular
Posts: 158
Joined: Mon Aug 12, 2013 11:28 pm
Projects: TBA
Organization: SenpaiJake Games/Paperviper
IRC Nick: dstar89
Deviantart: senpai-jake
Skype: dstar_891
Location: West Virginia, USA
Contact:

Re: Dungeon crawling RPG frame

#58 Post by Dragonstar89 » Mon Aug 19, 2013 4:11 am

Alright, I've mixed around with the code some (because I only need the battle part) and using of Dapnix's code, I've tried making a system. Only, my $ player.levelup() is activated when you reach certain EXP points which are defined as a variable instead of in an instance. But, the problem is with the $ player = Actor(etc. code here). It's bringing up the taking arguments in the traceback. Anyone know what's a miss? Here's my dummy script:

Code: Select all

# You can place the script of your game in this file.

# Declare images below this line, using the image statement.
image m normal = "normal.gif"
image m mad = "mad.gif"
image g normal = "g_normal.png"
image g mad = "g_mad.png"

# Declare characters used by this game.
define m = Character('Drenchin', color="#fdfdfd;")
define g = Character('Guard', color="#ff0000;")


# The game starts here.
label start:

    "Let's head into battle!"

    # Create skills (name, hit, power)
    $Slash = Skill("Slash", 70, 20)
    $Fire_Vein = Skill("Fire Vein", 35, 35)
    # Create battle actors (name, max_hp, stats, skills)
    $player = Actor("Hero",100, 1, 5, 5, 5, 5, 125, [Slash, Fire_Vein])
    $Guard = Actor("Guard",40,[Slash])
    
    jump battle

label afterbattle:

    if m_exp >=39:
        $ player.levelup()
        "Congratulations! You now have %(m_exp)d EXP points, and have leveled up to level %(lvl)d!"
        "Your stats are now: %(str)d STR, %(dex)d DEX, and %(int)d INT."
        return
    else:
        "Let's do another battle, shall we?"
        jump battle


label battle:
    show g normal at left with dissolve
    show m normal at right with dissolve

    $ enemy= Guard
    show screen battle_ui
    "[enemy.name] appeared"
    while enemy.hp>0:
        $ player.command(enemy)
        if player.hp <1:
            "gameover"
            $ config.rollback_enabled = True
    $m_exp +=20
    "You win"
    hide screen battle_ui
    jump afterbattle

# Using Python to define the Skill variables and instances

init -1 python: 
    # Class used for battle skills
    class Skill():
        def __init__(self, name, hit, power):
            self.name = name
            self.hit = hit
            self.power = power            
            
    # Class used for battle characters. Inherit renpy.store.object for the rollback function.
    class Actor(renpy.store.object):
        def __init__(self, name, lvl, str, dex, int, max_hp, skills=[]):
            self.name=name
            self.str = str
            self.dex = dex
            self.int = int
            self.lvl = lvl
            self.max_hp = 100
            self.hp = max_hp
            self.skills = skills

        def levelup(self):
            self.lvl += 1
            self.str += 1
            self.dex += 1
            self.int += 1

        def command(self, target):
            self.skill = renpy.call_screen("command")
            target.skill = renpy.random.choice(target.skills)
            self.attack(self.skill, target)
            if target.hp < 1:
                return
            target.attack(target.skill, self)
            
        def attack(self,skill,target):
            if self.skill.hit<renpy.random.randint (0,100):
                narrator ("{} dodged {}'s attack".format(target.name,self.name))
            else:
                target.hp -= self.skill.power
                narrator ("{} got {} damage".format(target.name, self.skill.power))

# Using screen lang of Renpy to create the buttons for attacks

init:
    # Screen used for selecting skills
    screen command:    
        vbox align (.5,.5):
            for i in player.skills:
                textbutton "[i.name]" action Return (value=i)

    # Screen which shows battle status
    screen battle_ui:    
        use battle_frame(char=player, position=(.95,.05))
        use battle_frame(char=enemy, position=(.05,.05))
        
    screen battle_frame:
        frame area (0, 0, 180, 80) align position:
            vbox yfill True:
                text "[char.name]"
                hbox xfill True:
                    text "HP"
                    text "[char.hp]/[char.max_hp]" xalign 1.0

*UPDATE*
I found it out, I wasn't defining the stats numbers right for the character's Actor definitions. :D
Beginning pre-production work on a project in Renpy. After being away for 5 years, it's time to get back in the game 8)

User avatar
OokamiKasumi
Eileen-Class Veteran
Posts: 1775
Joined: Thu Oct 14, 2010 3:53 am
Completed: 14 games released -- and Counting.
Organization: DarkErotica Games
Deviantart: OokamiKasumi
Location: NC, USA
Contact:

Re: Dungeon crawling RPG frame

#59 Post by OokamiKasumi » Wed Aug 21, 2013 9:50 pm

What a wonderful frame!
-- Is there a way to make a Specific maze? (What do all those 1s and 0s mean, and how can I use them to make a specific pattern?)
-- I'd also like to add several rooms as events. Basically, when you enter a certain part of the maze, it jumps to a room event where you get a prize. Once the player collects all the prizes one can exit.

Is this possible with this framework?
-- I have created something of what I'm after entirely in Renpy, but it uses a ton of jumps and takes a gigantic script.
Ookami Kasumi ~ Purveyor of fine Smut.
Most recent Games Completed: For ALL my completed games visit: DarkErotica Games

"No amount of great animation will save a bad story." -- John Lasseter of Pixar

User avatar
leon
Miko-Class Veteran
Posts: 554
Joined: Sun Oct 09, 2011 11:15 pm
Completed: Visual Novel Tycoon, Night at the Hospital, Time Labyrinth, The Buried Moon, Left of Center, Super Otome Quest
Projects: Lemon Project, Porcelain Heart, Dream's Dénouement
Organization: Team ANARKY
Contact:

Re: Dungeon crawling RPG frame

#60 Post by leon » Tue Sep 03, 2013 7:34 pm

I just wanted to drop by and say this is just genius! I've used it in Time Labyrinth and it worked great!

Also if anyone wants to create new maze designs, I made this SketchUp model. Just load it up, apply textures to your liking, hide some groups and export each background.

Post Reply

Who is online

Users browsing this forum: No registered users