DaFool wrote:I am sort of starting to get it, but I still have no clue as to what sort of parameter an 'Effect' is.
I'm not sure I know what you're asking, here... what do you mean by 'parameter'? When I use the word, I mean "value which is passed to a function/method", but I don't see how that fits into the sentence...
An Effect is a thing that you add to or remove from a Fighter, which makes some change to that fighter for the duration of its application. If you check in CurrentFighterPointer you can see the way it's added to or removed from the fighter:
Code: Select all
fighter.AddEffect("key", effectInstance)
...
fighter.RemoveEffect("key")
The 'key' can be anything, it's just to distinguish it from other effects and allow you to later remove the same instance that you added. The effectInstance has to be an instance of the Effect class (or a subclass of the Effect class) which you will generally get by calling the initialiser on the Effect you created:
Code: Select all
effectInstance = MyEffect(fighter, data, otherdata)
You have to supply at least the 'fighter' parameter, which is the fighter you're applying that effect to - the others are up to you - if you need any more information in your Effect (you probably don't, if you just want to display stat bars, since you can get them from the Fighter) then you'll need to pass it in here.
(As it goes, this is part of the API that I'm still not sure about, and I'm tempted to - in a later release - change Effect's constructor to not require a Fighter instance, or automatically apply an Effect when created. I'll try and make such changes in a minimal-impact way if I can.)
DaFool wrote:
(Correct me if I'm wrong, there hasn't been a demonstration of temporary effects such as 'Poison', etc., only 'Charmed' which is more of a Skill)
There's a 'HasteEffect' at the bottom of engine-extras.rpy which doubles a fighter's Speed for the duration of the Effect.
Basically, if you look at the definition of BattleAware, Extra, and Effect, you'll see a load of methods defined - most of them with no body, meaning they don't presently do anything. If you re-define one of those methods (e.g. FighterStartTurn) with the same parameter list in your own class, then that version will be called instead - meaning you can write code which runs whenever that event happens (so you could write code which attacks the Fighter with X poison damage every time his turn starts).
DaFool wrote:
Before I make my own AlternateCurrentFighterPointer, I first test the default one
...
Do I pass the name of a fighter, a graphic, or a status which I have to declare in its own class?
There should be two parameters - a Displayable which you want to use as a pointer, and a tuple of two values to use as an offset. But it seems that the code in there is old (pre-panning) and I'm not using it in any of the demos, so I didn't notice that I'd broken it when I did the panning changes. If you change the Show method of CurrentFighterPointerEffect (somewhere around line 463 of engine-extras.rpy) to the following,
Code: Select all
def Show(self, transforms=[], layer=None, zorder=None):
transforms = [self._fighter.Position.Transform]
offset = Transform(xoffset = self._offset[0], yoffset=self._offset[1])
transforms.append(offset)
renpy.show(self._tag, what=self._disp, at_list=transforms, layer=self._battle.GetLayer("Effects"), zorder=zorder)
and line 301 (I think) of engine-fighters.rpy from:
Code: Select all
self._battle.UnregisterForEvents(effect)
to
Code: Select all
self._battle.UnregisterForEvents(name)
then it should work. (These fixes will be included in Alpha 5.)
Then you can use it in a battle with something like:
Code: Select all
battle.AddExtra(CurrentFighterPointer(Image('gfx/pointer.png'), (0, -90)))
(I'll leave it in the active demo, I think, so I don't miss it again - thanks for the catch!)
DaFool wrote:
...Or let's start with something really, really simple... like a graphic of a smileyface which must be overlayed on top of all the sprites. Where exactly does the 'showing' of the graphic occur. How do you set it up? The reason I'm confused is because there are so many ui interface formatting interspersed throughout I'm not exactly sure where I can be free to declare a new screen or show a graphic.
OK, here's what I'd do:
- Create a new Effect - this will be the thing which actually draws the smiley face.
- On that Effect, create an __init__ method which takes three parameters: self, fighter and disp.
- Copy the first line of the __init__ method of CurrentFighterPointerEffect - this will make sure that the base class setup with the fighter gets done properly.
- Set a property on self to contain the disp - this is the graphic that we'll show when we want to draw the smiley face.
- Create a method called 'Show', which takes parameters: (self, transforms=[], layer=None, zorder=None) - this is an override of a method on the Effect, so when the Effect gets drawn by the engine your Show method will get called. In this method, you can call renpy.show and pass in the graphic we stored in a property of self. Like the fighter-select UI, it's best to give it a unique tag, so pick self._fighter.Tag and add a "smiley face" string to it or something. use self._fighter.Position.Transform in your at-list (that's the Transform which describes the fighter's position on-screen) and use a zorder of (fighter.Position.Z + 1) to make sure it gets shown above the fighter.
- Now we have the effect which will draw an arbitrary graphic over any fighter it's applied to, you'll need to add it to your fighters somehow. If you want it to show up all the time, then you could just create an instance of it for each fighter and add it to that fighter when you first create the fighters and add them to the battle - like that, they'll have the effect all the time.
- If you want to just show the smiley face when it's their turn, then you'll need to also create an Extra, which will be in charge of adding and removing the Effect when appropriate, and add that to your battle. To do this, you'll basically want to copy CurrentFighterPointer, which does a similar thing, only you wouldn't need the offset - it's hooking into FighterStartTurn and FighterEndTurn to add and remove the Effect from whichever fighter's turn is starting or ending.
Alternatively, I was going to do generic stat-bar support at some point (it's one of the features that the original Abraxas demo had, even!) so if you can hang on a bit you'll get it for free. If you don't have any luck making your own and it's something you're waiting on, I can move it up the priority queue a bit.
DaFool wrote:
Code: Select all
kbmbasic = 'gfx/kbmbase1.png'
renpy.show(name="kaboom", at_list=[], what=kbmbasic, layer=l, zorder=1000)
This is a Ren'Py thing - basically, there's three ways to specify a graphic: with a path to the graphic itself, with a Ren'Py-defined Image (as in "image eileen happy = "e_happy.png") or with a Displayable, which is a class Ren'Py uses internally to keep track of anything that can be displayed.
If you pass something to renpy.show, then it has to be a Displayable or the string name of a Ren'Py-defined image. So if you'd previously done "image explosion = 'gfx/kbmbase1.png' ", then you could pass what='explosion' into renpy.show... but as it is, you're telling it to look for an image which was previously defined in Ren'Py script with the name "gfx/kbmbase1.png" - so it's not looking for a graphic in your game directory, it's looking in Ren'Py's list of defined images.
You can define it previously (which is what I do in assets.rpy in the demos) or you can create an Image instance (a Displayable) passing in the path to load the image from a file:
Code: Select all
kbmbasic = Image('gfx/kbmbase1.png')
renpy.show(name="kaboom", at_list=[], what=kbmbasic, layer=l, zorder=1000)