Questions about DSB/ESB

This forum is for the Lua scriptable clone of DM/CSB called Dungeon Strikes Back by Sophia. Use DSB to build your own highly customised games.

Moderator: Sophia

Forum rules
Please read the Forum rules and policies before posting.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

Regarding the above question, I changed my approach so I don't need alpha channels now.

Another question though: is there a function that will activate the save game screen?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

To answer your prior question, if you draw a bitmap with dsb_bitmap_blit rather than dsb_bitmap_draw it will not respect the alpha channel, which in this case is what you want. You can also dsb_bitmap_clear a bitmap to set it to 0 (including 0 alpha) rather than using power pink.

There isn't currently a way to activate the save game screen via a command because the clickzone is set up in inventory_info and that is usually all anyone needs. What did you want to do?
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

Hmm, curious. How do I "also dsb_bitmap_clear a bitmap to set it to 0"..? What's the format for that? If I use dsb_bitmap_clear(bmp, {0,0,0}) that's just cleared to black as expected (not what I want, it needs to be transparent). If I use dsb_bitmap_clear(bmp, 0) that's invalid and crashes.

For the save button, I tried something where the save button is displayed elsewhere on screen, not within the inventory. For that to work, I'd need a function that I can call from a clickzone message, maybe dsb_show_gui() that just activates the save game dialogue as usual. It doesn't matter now, I reverted to an older design, but it might be a useful function to add for future designer possibilities? And also a dsb_sleep() for similar reasons... there is a dsb_wakeup() after all ;-)
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

When you dsb_bitmap_clear a bitmap, it also sets the alpha channel to 0. The background can be black, power pink, or whatever, because it isn't drawn, so normally you don't even notice.

The problem I think you're having is that due to DSB's old-fashioned means of rendering stuff, drawing images with an alpha channel takes more CPU power so it disables the alpha channel when it thinks it doesn't need it. Normally drawing an image with actual alpha channel information to the bitmap should suffice but if something isn't working right the easiest workaround is to "poke" it with a single pixel that sets an alpha value (which can be 0) which will cause DSB to respect the alpha channel for that bitmap again.

Code: Select all

function clear_with_alpha(b, clearcolor)
	dsb_bitmap_clear(b, clearcolor)
	dsb_set_pixel(b, 0, 0, clearcolor, 0)
end
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

Thanks, I've now tried this but it doesn't seem to work with sys_render_other. For example, this still creates a pink fringe around gfx.alpha, which is a test image of a green circle with a soft edge that requires alpha blending. Am I still doing something wrong, or is this not supported in sys_render_other?

Code: Select all

function sys_render_other(bmp, gui_name, frozen)
	clear_with_alpha(bmp, color.powerpink)
	dsb_bitmap_draw(gfx.alpha, bmp, 20, 20, false)
end
Image

Using dsb_bitmap_blit is even worse, with all sorts of junk drawn around and behind gfx.alpha. Despite re-reading your last couple of comments, I'm now totally confused by this, as I thought I had a really good grasp of the differences between using draw or blit functions and this isn't behaving how I'd expect?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

You're clearing the background to power pink and then drawing an image with alpha, which gets blended with the power pink. If you want to use dsb_bitmap_draw then you want to clear the screen to black, which essentially makes it work like pre-multiplied alpha.

Can you post a screenshot of what dsb_bitmap_blit looks like? There may be an underlying issue because "all sorts of junk" showing up is usually a bug.

EDIT: Nevermind. I just checked the code and apparently the various system renderers don't respect alpha channels at all. I'll fix this for DSB 0.77.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

If I clear the bitmap to black, then it's displayed black, even when forcing an alpha pixel as you described. That's no good, the whole bitmap needs to be cleared to transparent, so that I can draw alpha images on top of it. The only way I get a transparent cleared bitmap is to fill it with powerpink.

Here's the same example using dsb_bitmap_blit, with this code:

Code: Select all

function sys_render_other(bmp, gui_name, frozen)
	clear_with_alpha(bmp, color.powerpink)
	dsb_bitmap_blit(gfx.alpha, bmp, 0, 0, 20, 20, 100, 100)
end
Image

EDIT: Aha, OK, just saw your edit. Phew, at least I'm not gong mad, thanks. ;-)
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

What is this for in render.lua? I don't see any other instance of 'rend_method_check' in the base code?

Code: Select all

if (arch.rend_method_check) then
    if (not arch.rend_method_check(iobj)) then
        icon = nil
    end
end
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

It isn't actually used by the base code. It's for designers to create an item that only offers attack methods under specific circumstances; if rend_method_check is defined and returns false, no attack method icon is drawn and thus no attack methods are offered.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

OK, cool thanks. Another question:
For monsters with less than 4 bitmaps, what is happening internally in the engine with these? Do they still have unseen side and rear views, ie, DSB still rotates these creatures around the full axis of views even though we don't see some of them? So when a screamer is moving/facing away and the player catches up with it, does it turn to the side before turning to face us, or does it face the player immediately?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

All monsters internally have a facing, and a monster without certain bitmaps defined is handled internally exactly the same as if the bitmaps had been defined. This means that there would be turning delays and such. However, the instant_turn property negates this, and is set on all DM monsters with only a front bitmap. Any monster with instant_turn set to true will ignore any turning animations or delays and always instantly face the party.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

OK, great thanks, I thought it might be something like that. God to know, cheers.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

Is there a way of setting a global variable to true when a subrenderer is displayed, and false when it isn't? Or is there some internal condition I can test?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

I think you'll have to clarify what you mean by "when a subrenderer is displayed," because some sort of bitmap that the code considers a subrenderer is being drawn any time you're on the inventory screen. Or do you mean specifically only when an object is held in hand? Because then you could just use dsb_fetch to check for that, and then see if its arch has a subrenderer defined.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

Hmm, I'm not actually sure. I will think about this some more...! I'm trying some weird stuff but may simply have messed something up...
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

OK, I thought about the problem some more, and I need to ask a different question: is it possible to draw something bigger than the subrenderer area within a subrenderer function?

I know I can use sys_render_other to render anything I want wherever I want, but that can have "layering"* problems that aren't easy to solve. Subrenderers solve their own layering issues, so I'd like to keep my code still working within a subrenderer, rather than moving the responsibility over to sys_render_other.

Basically, I'd like to have custom sized subrenderers :) -- but I know this is probably a whole world of hurt at this point in DSB's evolution.

If custom sized subrenderers are unlikely, then the reason I wanted a true/false flag was for this sort of scenario:

Code: Select all

function sys_render_other(bmp, gui_name, frozen)
	if (gui_name == "extra_subrender_ui") then
		if (current_visible_subrender == "chest")
			-- draw some extra stuff in the inventory area
			-- that's bigger than the chest subrender size
		end
	end
end
But I guess I could do this by testing for items in the player's right hand instead...? However, even if this approach would work, I still think there would be layering issues, which is why I'd prefer to do all this within the subrender functions which seems to manage layering automatically much better.

Code: Select all

function sys_render_other(bmp, gui_name, frozen)
	if (gui_name == "extra_subrender_ui") then
		if (ITEM_IN_RIGHT_HAND() == "chest")
			-- draw some extra stuff in the inventory area
			-- that's bigger than the chest subrender size
		end
	end
end
* By layering, maybe read "rendering priority order".
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

If I'm correctly understanding the problem that you are having, the issue is that sys_render_other is called before any subrenderers are drawn onto the inventory bitmap, so that anything you add will appear to be "under" the subrenderer. If this is all it is, it seems like the easiest thing for me to do would be to add an option to change the draw order.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

I'm saying entirely the wrong thing, because that's not the problem I'm having :D

sys-render-other does indeed render over everything else, including sub renderers, and that's normally fine. However, I've sort of hacked sys-render-other to simulate an empty handed mouse click on the eye to display stats, but the way I've done this does not behave the way that it would work with the subrenderer approach.

In standard DSB DM, a click on the mouth or eye activates the food or stats subrenderers, but you can still move the mouse outside the clickzone for the eye or mouth. Nothing visually changes: the mouse cursor isn't displayed in these cases anyway, and the subrenderers continue to display even though the mouse is no longer technically within the original clickzone.

I want my sys-render-other "stats eye click" function to work the same way, but it doesn't.

I check if the mouse position is the same as the click zone for the eye and if the left button is pressed, and if so, I draw the stats screen. This works fine if you don't move the mouse after those conditions are met, but if you *do* move the mouse outside the clickzone, the stats panel vanishes (as I would expect) but NO subrenderer is drawn underneath, so there is a big empty space. I don't really understand why to be honest, but that's the problem I'm trying to solve. Here's the simplified code for that:

Code: Select all

function sys_render_other(bmp, gui_name, frozen)

	local mx, my, leftclick, rightclick = dsb_mouse_state()

	-- Stats (empty mouse on eye)
	if (gui_name == "stats") then

		-- If holding an item in mouse hand, don't show the stats
		local mouse_obj = dsb_fetch(MOUSE_HAND, 0, 0, 0)
		if (mouse_obj) then return end

		-- Get the character for the current open inventory
		local current_inv_ppos = dsb_current_inventory()
		if (current_inv_ppos) then

			local who = dsb_ppos_char(current_inv_ppos)
			local ix = gui_info.viewport.x + inventory_info.eye.x
			local iy = gui_info.viewport.y + inventory_info.eye.y
			local iw = ix + 32
			local ih = iy + 32

			-- Mouse button 1 pressed (left click)
			if (leftclick) then

				-- If mouse within the eye icon area:
				if (mx >= ix and my >= iy and mx <= iw and my <= ih) then

					-- Render the stats for the (who) champion

				end
			end
		end
	end
end
The reason I wanted some kind of flag to know which subrenderer is being displayed, is to fix this above problem: I can use that flag to conditionally draw the correct subrenderer if the player moves their mouse outside the eye click zone. Of course, an even better solution is not to need this, and for the stats to still be drawn even if the mouse goes outside the x/y/w/h click area in my code above.

I appreciate this all sounds like a huge mess and now that I've written this explanation, I can see that it is indeed a mess and not a good approach!

Which is why I'd love to be able to create different sized subrenderers, because all of these problems go away with subrenderes as you handle all the above issues automatically "behind the scenes".

I've been fiddling with this for days now and I'm not even sure if any of the above even makes any sense anymore....!?!?!?! I hope you can help unpick this or propose a better solution in some shape or form anyway? :)
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

Ok, I still don't really understand what you're trying to do, but I'll do my best to help you.

The reason why the stats panel disappears if you move the mouse is because that's what your code does. You check if the left mouse button is down, and then, inside of that loop, you check if the mouse is within a certain rectangular box. If the mouse button is down but the mouse is no longer within that rectangle, then the inner condition is no longer met and your rendering code is not executed.

I should ask, how are you actually rendering the stats? If you're just calling the normal function, then you're calling dsb_subrenderer_target outside of an actual subrenderer, and if dsb_subrenderer_target is called outside of an actual subrenderer, the behavior is undefined. I should probably just fix DSB so trying to do that simply won't work at all. It seems like the "immediate mode" GUI approach of DSB is causing you some trouble here, because you ultimately want to check for a click in one rendering function in order to influence what happens in a different rendering function.

Anyway, my suggestion would be to change your code to something like this:

Code: Select all

use_ch_exvar(who)
if (leftclick) then
  if (within_rectangle) then
    ch_exvar[who].draw_stats = true
  end
else
  ch_exvar[who].draw_stats = nil
end
Then, within your inventory subrenderer, you can check the ch_exvar for the currently displayed character and draw the stats or whatever you want. This allows you do the actual rendering within your subrenderer, which is what you wanted. Alternatively, you could use a global temporary variable instead of associating it with a character exvar.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

Sophia wrote: Fri Apr 17, 2020 1:18 amThe reason why the stats panel disappears if you move the mouse is because that's what your code does. [...]
Yep, I know, as noted above. But why does the subrenderer that was previously shown "underneath" also disappear when this happens? Let's say the food subrender was showing, it vanishes completely when the mouse is moved outside my eye clickzone as setup in sys-render-other. I don't really understand why? Maybe I need to send you an update zip...
Sophia wrote: Fri Apr 17, 2020 1:18 amI should ask, how are you actually rendering the stats? If you're just calling the normal function, then you're calling dsb_subrenderer_target outside of an actual subrenderer, and if dsb_subrenderer_target is called outside of an actual subrenderer, the behavior is undefined.
I've copied the code from the subrenderer directly into my sys-render-other function, so no, I don't call any subrenders, I'm just generating a big stats bitmap over the whole screen but using some conditional checking to ensure it only happens during an open inventory. The original stats subrender (that would normally happen with an empty mouse click on the eye) has been disabled by returning true from the h_custom_stats hook function.
Sophia wrote: Fri Apr 17, 2020 1:18 amAnyway, my suggestion would be to change your code to something like this:

Code: Select all

use_ch_exvar(who)
if (leftclick) then
  if (within_rectangle) then
    ch_exvar[who].draw_stats = true
  end
else
  ch_exvar[who].draw_stats = nil
end
Then, within your inventory subrenderer, you can check the ch_exvar for the currently displayed character and draw the stats or whatever you want. This allows you do the actual rendering within your subrenderer, which is what you wanted. Alternatively, you could use a global temporary variable instead of associating it with a character exvar.
Hmm, ok thanks, but I can't see how this helps? I think this is the opposite of what I need? If I end up drawing the stats within the subrenderer, then it can only be 246x146, and the whole reason for these shenanigans is that I have a bigger stats panel now, so that the text is more readable than DMs old super-cramped UI. And if I'm drawing stats in the subrenderer, then I don't need anything to be setup in sys_render_other anyway?

Basically I just want to be able to have a bigger stats panel displayed when the player clicks on the eye with an empty mouse cursor. I previously shared the visual for this on a PM. As this can't be done in the usual subrenderer due to it having a fixed size, are there any other methods I could use, other than this big old hack I've been trying to implement? 🤔 I don't particularly care how it's done as long as it works and works in the same way as the eye and mouth subrenderers do: that if the user happens to move the mouse outside the clickzone, the larger stats will continue to be displayed.
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

Ok, now I understand what you're trying to do. It seems like the easiest approach is to just give you some way you can query that the eye is being held down, so you can just check for that and render the appropriate thing.

The reason the subrenderer is blank is probably because DSB is trying to draw the standard stats subrenderer and, as you've noted, you've gotten rid of all of that. So when the mouse is held down but not within the eye, your code is no longer being triggered but the standard DSB code still is, so it just ends up blank.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

I managed to fix this really simply in the end (although I'm not sure if the solution is "correct"?) I've set a global "eyeClicked" var as false by default, then updated the h_custom_stats hook to:

Code: Select all

function h_custom_stats(who, final)
	eyeClicked = true
	return true
end
Then in my sys_render_other function to render the larger stats view, I've removed the left click and coordinates tests and instead just test for "eyeClicked". At the end of the stats drawing routine, I set eyeClicked back to false. This has the effect of trapping the mouse effectively in the subrender code (which is just the blank hook), because obviously this particular subrenderer is only active when the mouse is already being held down over the eye. Now my larger stats are displayed correctly, and they continue to display even if the mouse is moved outside the eye while clicked, so the behaviour now matches the original eye/mouth subrenderers. Awesome!

Of course, this does mean the eyeClicked variable is rapidly changing states while trapped in this setup -- does that have the potential to break the game timing/performance? I imagine this probably isn't an ideal solution really...?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

What you ended up doing is very similar to how it would work once I added the feature I mentioned above. If you could query the engine directly to find out that the eye is being clicked, you could just do that; this code does about the same thing, just a bit less elegantly since you can't actually do that yet. So, there is no real performance issue here, it's just a bit messy. The good news is that once I've added the new function it'll be really easy to change over since your method is very similar.
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

For 0.77 I've added dsb_get_lookmode which will work very similarly to what you're trying to do, only without the need of any global variable hacks.

Code: Select all

local eyeclicked, mouthclicked = dsb_get_lookmode()
(In standard DM, a return value of true, true is not possible)
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

Great, thanks! :)

In sys_render_attack_result, how can I determine which champion made the attack?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

That information isn't actually preserved anywhere currently. For 0.77 I'll add dsb_get_attackppos which will return the party position of the currently displayed attack result graphic. You can then call this in your renderer function.

Since you'll now know the ppos, you'll then be able to call (the already existing function) dsb_get_lastmethod(ppos) to get information about the attack method that was used.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

I'm using the multidraw property to have two wallitems render together in the DM dungeon. Works great for rendering, but interaction is weird:

If I add a dsb_write() into the on_click handler for each of the objects, I would expect two messages written to screen for each single click on the wall, for example:

Code: Select all

Mirror clicked
Mirror overlay clicked
However, what I actually get is this:

Code: Select all

Mirror clicked
Mirror overlay clicked
Mirror overlay clicked
Mirror clicked
How can I get this to only show one message for each wall item?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Questions about DSB/ESB

Post by Sophia »

When DSB is in "draw one wallitem per wall" mode, a click on any wallitem propagates click messages to any other wallitems on the same wall. Normally that's what you want, but if you're using multidraw, then you have two wallitems (and thus two clickzones) being drawn, so the weirdness you're seeing is as follows:

Code: Select all

Mirror clicked           <-- Clickzone 1
Mirror overlay clicked   <-- Propagated click from Clickzone 1 
Mirror overlay clicked   <-- Clickzone 2
Mirror clicked           <-- Propagated click from clickzone 2
The simplest fix for your case is probably to just not propagate clicks to or from multidraw wallitems. This creates a few problems in itself but since multidraw is sort of a hack anyway, I'm not really concerned. I'll call this fixed for 0.78.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

Cool, OK, sounds good to me! Thank you.
User avatar
Gambit37
Should eat more pies
Posts: 13715
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Questions about DSB/ESB

Post by Gambit37 »

Is there a way of finding out the wallset of a specific tile (ie, one that was painted in ESB wall painting mode). dsb_fetch() doesn't yield that info and I couldn't find anything in the wiki under wallsets.
Post Reply