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
DapNix
Regular
Posts: 52
Joined: Fri Mar 01, 2013 6:15 am
Contact:

Re: Dungeon crawling RPG frame

#61 Post by DapNix » Mon Oct 21, 2013 2:23 pm

It's been a while since I've been here, and now after some months I've decided to take up on my old games. I can do pretty nice combat systems, but there is one thing I always get stuck on, and this is propably something that I'll be stuck on for a long time, so I figured I'd come here to ask some people of more knowledge than myself on the subject.
On a scale from 1 to 10, how impossible is it to add special effects to attacks? Such as a stun, disabling the players ability to attack on the next turn, or a bleed/poison that deals damage per round for a set amount of rounds?
This is something I've been working on for a long time, but I haven't made any progress whatsoever, and I reaaally feel like after nailing this part of a battle code I'll be off to finish my old projects and make a full story! :)
Would love some help!

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

#62 Post by Anima » Mon Oct 21, 2013 5:08 pm

The basic idea I usually use is to have every effect as an object. Simply store all effects in a list on the character and iterate trough it at the beginning of her turn. During the iteration you make two calls. One to the effect objects do method and another to it's expired method. The do method does whatever the effect does to her and the expired method handles duration.

How to implement these in detail depends on the kind of system you want to use and how your other data structures are.

To implement a stun effect for example you can go two ways. Either you simply have the attack set a stun flag directly on the character that is checked when her turn comes up next and then reset after it's gone. Or you treat it as an effect and either have the code search trough her effect list for a stun effect to check if she can act. Or have the effect set a stun flag in the do method and the flag reset either in her turn end method or in the expired method of the effect.

The advantage of the second version is that you do not need any special provisions for displaying the stun status, since whatever you use for effects in general will work for the stun effect as well.
Avatar created with this deviation by Crysa
Currently working on:
  • Winterwolves "Planet Stronghold 2" - RPG Framework: Phase III

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

Re: Dungeon crawling RPG frame

#63 Post by DapNix » Tue Oct 22, 2013 11:31 am

Anima wrote:To implement a stun effect for example you can go two ways. Either you simply have the attack set a stun flag directly on the character that is checked when her turn comes up next and then reset after it's gone. Or you treat it as an effect and either have the code search trough her effect list for a stun effect to check if she can act. Or have the effect set a stun flag in the do method and the flag reset either in her turn end method or in the expired method of the effect.
The way I'd prefer it to be is to have a character icon on the lower left part of my screen. For instance, have it be the face of my character. If stunned, we would add a sort of petrifying effect to the picture to signalize the stun effect. Or if poisoned, we would add a green-ish color to the picture to then signalize the poison effect.
Would a similar type of code be used when doing the opposite of these status ailments. Such as doing buffs?

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

Re: Dungeon crawling RPG frame

#64 Post by DapNix » Tue Oct 22, 2013 12:57 pm

(Adding a side-note)
Be gentle, I know enough to make battle systems, but when it comes to status ailments and such I have no experience whatsoever. Any help is appreciated though!

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

#65 Post by Anima » Tue Oct 22, 2013 2:15 pm

Yes it would.
(I should add the changing the character portrait is an elegant way to show status changes, but it doesn't work very well if the character can have more than one status. Combinatorial explosion rears it's ugly head there.)

And please don't double post if you want to add something, you can edit your post.
Avatar created with this deviation by Crysa
Currently working on:
  • Winterwolves "Planet Stronghold 2" - RPG Framework: Phase III

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

Re: Dungeon crawling RPG frame

#66 Post by DapNix » Tue Oct 22, 2013 3:26 pm

Beginning to get what you're saying, and sorry for the double post. Do you think you could make a short example for me to off of?
I'll just post my code in here, wanted to change with the class Actor but through trial and error I haven't made much progress.

Code: Select all

label start:
    # Create skills (name, hit, power, type)
    $Slash = Skill("Slash", 90, 335, "attack") 
    $Pound = Skill("Pound", 90, 120, "attack")
    $Decapitation = Skill("Decapitation", 80, 510, "attack")
    $FreeStrike = Skill("Free Flowing Strike", 100, 420, "stun") 
    $Precision = Skill("Precision", 100, 150, "attack")  
    
    # Create battle actors (name, max_hp, skills, type)
    $player = Actor("Nix",2100, [Slash, Decapitation, FreeStrike])
    $Demon = Actor("Demon",6300,[Pound, Precision])
    

label battle:
    show screen battle_ui
    "Demon appeared"
    while Demon.hp>0:
        $ player.command(Demon)
        if player.hp <1:
            "gameover"
            $ renpy.full_restart()
    "You win"
    hide screen battle_ui
    $ player.reset(Demon)
    jump story
    
init -1 python:
    from copy import copy    
            
    class Skill():
        def __init__(self, name, hit, power, type):
            self.name = name
            self.hit = hit
            self.power = power   
            self.type = type         
            
    class Actor(renpy.store.object):
        def __init__(self, name, max_hp=0, skills=[]):
            self.name=name
            self.max_hp=max_hp
            self.hp=max_hp
            self.skills = skills
            
        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 ("{} nimbly dodges {}'s attack".format(target.name,self.name))
            elif self.skill.type=="stun":
                target.hp -= self.skill.power-renpy.random.randint (0,30)
                narrator ("{} stuns {} with a powerful blow!".format(self.name,target.name))
            else:
                target.hp -= self.skill.power-renpy.random.randint (0,28)
                narrator ("{} strikes {}!".format(self.name,target.name))

        def reset(self, target):
            self.hp = self.max_hp
            target.hp = target.max_hp
    
init:           
    screen command:    
        vbox align (.05,.9):
            for i in player.skills:
                textbutton "[i.name]" action Return (value=i)

    screen battle_ui:    
        use battle_frame(char=player, position=(.05,.05))
        use battle_frame(char=Demon, position=(.95,.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


label story:
    "That wasn't too hard, was it?"
    call battle
As you can see I've added types into my skills, so one of my moves has the type "stun". I tested to see if it worked with the

Code: Select all

            elif self.skill.type=="stun":
                target.hp -= self.skill.power-renpy.random.randint (0,30)
                narrator ("{} stuns {} with a powerful blow!".format(self.name,target.name))
and sure enough it added new dialogue. Now all I need is a proper way to add the function. Any suggestions?

User avatar
rabcor
Regular
Posts: 81
Joined: Sun Mar 17, 2013 3:07 pm
Projects: None (Need a programmer?)
Organization: Cestarian Games
Contact:

Re: Dungeon crawling RPG frame

#67 Post by rabcor » Thu Nov 21, 2013 2:21 pm

Thanks a whole lot for this nyaatrap, this thread and it's contents have been really helpful!

But the binary map you have in the lower right corner of your screenshot doesn't seem to be showing up with your example code/game, a minimap system seems pretty important for a dungeon crawler so how can i make it or make it show?

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

#68 Post by nyaatrap » Thu Nov 21, 2013 4:31 pm

A code showing minimap on the demo was obsoleted. I'm uing sprite manager now, but explaining it is hard. I'd just paste my code:

Code: Select all

    # Class used for stages 
    class Stage(object):
        def __init__(self, name, map):
            self.name=name
            self.map = map
            self.mapped=[]
            for n,i in  enumerate(map):
                self.mapped.append([])
                for j in i:
                    self.mapped[n].append(0)                    
            
    # Class used for relative coordinate
    class Coordinate(object):
        def __init__(self,stage,y,x,dy,dx):
            self.stage=stage
            self.y=y
            self.x=x
            self.dy=dy
            self.dx=dx

    # Class used for minimap. minimap(coordinate).sm shows it.
    class minimap(object):
        def __init__(self,child):
            self.sm = SpriteManager(ignore_time=True)            
            for n,i in enumerate(child.stage.map):
                for m, j in enumerate(i):
                    if child.stage.mapped[n][m]==1:
                        if j == "1":
                            d = Solid("#666", area=(0,0,12,12))
                        else:
                            d = Solid("#fff9", area=(0,0,12,12))
                    else:
                        d = Solid("#0000", area =(0,0,12,12))
                    self.add(d,n,m)
            if child.dy==-1:
                    d = Transform("gui/arrow.png", rotate=180)
            elif child.dx==1:
                    d = Transform("gui/arrow.png", rotate=270)
            elif child.dy==1:
                    d = "gui/arrow.png"
            else:
                    d = Transform("gui/arrow.png", rotate=90)
            self.add(d,child.y,child.x)
        
        def add(self, d,n,m):
            s = self.sm.create(d)
            s.x = 1080+m*12
            s.y= 460+n*12

screen move:
    add minimap(here).sm

User avatar
rabcor
Regular
Posts: 81
Joined: Sun Mar 17, 2013 3:07 pm
Projects: None (Need a programmer?)
Organization: Cestarian Games
Contact:

Re: Dungeon crawling RPG frame

#69 Post by rabcor » Fri Nov 22, 2013 9:44 am

Sorry for being a noob but how do i actually make that code work? i just get this error if i copy that code in alongside the OP code.

Code: Select all

File "game/Class.rpy", line 2: expected statement.
    class Stage(object):
                  ^

File "game/Class.rpy", line 13: expected statement.
    class Coordinate(object):
                         ^

File "game/Class.rpy", line 22: expected statement.
    class minimap(object):
                     ^
Also when i tried to use the code from page 2 (i'm supposed to replace the "init" for #Assign Background Images. with this code right?)

Code: Select all

for i in ["left3", "right3", "left2", "right2", "front2", "left1", "right1", "front1"]:
                j=globals()[i]
                try:
                    if j.map[j.y][j.x]=="1":
                        renpy.show(i)
                except: pass
I get a similar error

Code: Select all

File "dungeon.rpy", line 170: expected statement.
    for i in ["left3", "right3", "left2", "right2", "front2", "left1", "right1", "front1"]:

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

#70 Post by Anima » Fri Nov 22, 2013 10:09 am

All the class definitions need to be in a python block.

Code: Select all

python:
    class ...
Avatar created with this deviation by Crysa
Currently working on:
  • Winterwolves "Planet Stronghold 2" - RPG Framework: Phase III

User avatar
rabcor
Regular
Posts: 81
Joined: Sun Mar 17, 2013 3:07 pm
Projects: None (Need a programmer?)
Organization: Cestarian Games
Contact:

Re: Dungeon crawling RPG frame

#71 Post by rabcor » Fri Nov 22, 2013 11:43 am

Thanks, that makes the game run with the minimap code on. but it doesn't seem to actually use the code (i don't get any minimap nor errors related to it, even if i know i don't have the image files it requests) i'm guessing i somehow have to tell script.rpy to use minimap, right? (Sorry for being such a pain :oops:, i'm relatively new to this)

Currently reading this hoping to find some clues.

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

#72 Post by Anima » Fri Nov 22, 2013 12:11 pm

Yes you need the show screen command.
Avatar created with this deviation by Crysa
Currently working on:
  • Winterwolves "Planet Stronghold 2" - RPG Framework: Phase III

User avatar
rabcor
Regular
Posts: 81
Joined: Sun Mar 17, 2013 3:07 pm
Projects: None (Need a programmer?)
Organization: Cestarian Games
Contact:

Re: Dungeon crawling RPG frame

#73 Post by rabcor » Fri Nov 22, 2013 12:32 pm

still not figuring it out, although i did notice that i didn't read the comments in nyaatrap's code well enough. If i really do need the "show screen" command, i'm not sure where to use it or what to write in exactly.

Code: Select all

# Class used for minimap. minimap(coordinate).sm shows it.
i try using it in script.rpy, uncertain where to actually add it. I've tried a few things but nothing seems to work (i either get errors or just exactly nothing)

But i think i need to use the other classes as-well. (class Stage(object) and class Coordinate(object))

User avatar
chris3spice
Regular
Posts: 44
Joined: Wed Nov 20, 2013 12:39 am
Projects: BKA24
Location: Kansas
Contact:

Re: Dungeon crawling RPG frame

#74 Post by chris3spice » Fri Dec 13, 2013 2:38 am

rabcor, have you gotten the mini-map to work?

I've tried but can not get it to run in my code either, I'm stuck on the error "Position has no attribute stage"

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

Re: Dungeon Crawl RPG Framework 2.0

#75 Post by nyaatrap » Mon Feb 17, 2014 5:19 am

Rewrite the framework from scratch. The new code is more sophisticated, but there's no compatibility with former versions. It also uses new style syntax of ren'py 6.17.
Dungeon script and battle script are now separated, and minimap is also implemented.

Post Reply

Who is online

Users browsing this forum: No registered users