-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementation of scriptable sprite overlays. #120
base: oxce-plus
Are you sure you want to change the base?
Conversation
After some discussions with SupSuper I may have come up with an even better way of doing this, so I've converted this to a draft as I explore that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initial batch of review
src/Savegame/BattleUnit.cpp
Outdated
@@ -5846,6 +5846,10 @@ void setFireScript(BattleUnit *bu, int val) | |||
} | |||
} | |||
|
|||
void getStatusScript(const BattleUnit* bu, int& status) | |||
{ | |||
status = bu ? bu->getStatus() : status; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
result value should be deterministic, now is "random", set 0
or any other value when nullptr
was given.
src/Savegame/SavedBattleGame.cpp
Outdated
@@ -3493,6 +3493,16 @@ void getTileScript(const SavedBattleGame* sbg, const Tile*& t, int x, int y, int | |||
} | |||
} | |||
|
|||
void getEnvrionmentShockIndicator(const SavedBattleGame* sbg, const Surface*& shockIndicator) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No guard for nullptr
src/Savegame/SavedBattleGame.cpp
Outdated
auto* enviro = sbg->getEnviroEffects(); | ||
auto* mod = const_cast<Mod*>(sbg->getMod()); | ||
shockIndicator = enviro && !enviro->getInventoryShockIndicator().empty() ? mod->getSurface(enviro->getInventoryShockIndicator(), false) | ||
: mod->getSurface("BigShockIndicator", false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting (good to keep 80 line limit, especially when you have ?:
)
src/Mod/Mod.cpp
Outdated
*/ | ||
void getInterfaceElementColor(const Mod* mod, int &color, const std::string& interfaceName, const std::string& elementName) | ||
{ | ||
auto interface = mod->getInterface(interfaceName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
none nullptr
guard
src/Mod/Mod.cpp
Outdated
*/ | ||
void getInterfaceElementColor2(const Mod* mod, int& color, const std::string& interfaceName, const std::string& elementName) | ||
{ | ||
auto interface = mod->getInterface(interfaceName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
none nullptr
guard
class SavedBattleGame; | ||
|
||
/// Namespace for segregating SpriteOverlay scripting functions. | ||
namespace SpriteOverlayScript |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not simply make it member functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking was twofold.
- I didn't want to expose general consumption methods that probably shouldn't be called outside the scripting context. That is, all of these draw and blit methods really shouldn't be called by other C++ code. Such behavior is probably incorrect. But, for convenience's sake, I wanted to give them access to private data and avoid writing many pointless getter functions.
friend
-ing the class seemed to be the best way to compromise these two goals. - Less so for this method, but for the
InventorySpriteContext
, I was exposingenum
s in funky ways (asint
s) for the scripting that I normally wouldn't. Again I wanted to conceal this from the general consumption code, so I applied the same method. These properties are public so it probably could have been just free functions instead, but I thought I would stick with this approach.
I used normal member functions in the (few) cases where I thought it was reasonable for both scripting and general code to use the same method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it could be private members, as ScriptRegister
is part of class it can access private bits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't realize that. Rewrite with this in mind incoming.
src/Battlescape/SpriteOverlay.cpp
Outdated
/// Draws a number on the surface the sprite targets. | ||
void drawNumber(SpriteOverlay* dest, int value, int x, int y, int width, int height, int color) | ||
{ | ||
dest->_numberRender.clear(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
none nullptr
guard
src/Battlescape/SpriteOverlay.cpp
Outdated
/// Draws text on on the surface the sprite targets. | ||
void drawText(SpriteOverlay* dest, const std::string& text, int x, int y, int width, int height, int color) | ||
{ | ||
auto surfaceText = Text(width, height, dest->_bounds.x + x, dest->_bounds.y + y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
none nullptr
guard
const auto surfaceSet = *_game->getMod()->getSurfaceSet("BIGOBS.PCK", anim); | ||
InventoryItemSprite(*firstAmmo, save, *_selAmmo, spriteBounds).draw(surfaceSet, InventorySpriteContext::SOLDIER_INV_AMMO, anim); | ||
|
||
constexpr auto handSlotBounds = SDL_Rect{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check mods like WH40k use bigger hands items than normally allowed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested. The mod uses a custom sprite that fakes the appearance of a bigger box for hand items. The current behavior is maintained for these items, though this patch offers some options for handling customizations in these cases.
update of src/OpenXcom.2010.vcxproj.filters is missing for display in Visual Studio update of src/CMakeLists.txt is missing for compilation on Linux, Mac and Android |
Sorry for the spam, didn't mean to close this. Had to update the filter file manual, could not for the life of me get visual studio to do it. |
In week or two I will go back to this PR and analyze it in detail and possibly alter it a bit and merge manually. |
Okay while I could keep fiddling with this forever, I think it's ready for review.
Notes on my approach:
InventoryItemSprite
andSpriteOverlay
.InventoryItemSprite
is similar toItemSprite
andUnitSprite
. It takes on all responsibility for drawing InventoryItems/bigobs. It is non-owning and should not leave the local scope. This was necessary to cleanly provide a centralized way to enable or disable the rendering of various (now) optional behaviors. It also eliminates a small amount of code duplication. This also represents the biggest structural changes to the code since the logic that powered these effects is removed and moved into this class.InventoryItemSprite
depends on a small struct,InventorySpriteContext
to inform the scripting engine of the current context in which the inventory sprite is being rendered and allows for the scripts to instruct the class to render or not-render the various options.InventorySpriteContext
also contains a set of static values representing the current OXCE behavior (Wound overlays are only drawn on units on the ground. Ammo counts do not show up in the inventory screen). I believe there is a good argument for changing some of these defaults, but I have left it as is for now. I considered exposing it to the rule files but decided it was too much work/too intrusive, and the behavior can be adjusted by scripting anyways.InventoryItemSprite
itself has no exposure to scripting, which is all handled bySpriteOverlay
andInventorySpriteContext
friend
ed, and tucked away in their own namespace. This lets them access private data where necessary but does not blot up the API with calls that are not relevant outside the scripting language.SpriteOverlay
is the primary interface for the scripting engine and holds most of the state information needed to perform the scripting (primarily the sprite bounds and the target surface).SpriteOverlay
in the local scope (it should not leave the local scope and is non-owning of any resource) and then call thedraw
method on it.draw
is a template function and providing the appropriate templates lets the appropriate scripts be called with the appropriate arguments.inventorySpriteOverlay
which is called in the context of rendering an inventory sprite (anywhere it might be rendered, except the UFOpedia at this time). It exposesBattleItem
data.handOverlay
which is called in the context of rendering a hand-slot, which is commonly bigger than the sprite. Handslot sized render boxes are also used for the hover ammo box and items selected by the cursor, so it is also called in these contexts, though it has no effect by default. It exposesBattleItem
data.unitPaperdollOverlay
which is called when the paperdoll is rendered. It exposesUnit
data.unitRankOverlay
which is called when the unit rank is displayed on the battlescape.I think that about covers it. I had other things in the past, but on further consideration, I backed off from them so this is pretty much only exactly what it says on the tin. There are a few additional scripting methods thrown in that I found necessary to generate the demo effects, which probably means they are generally useful regardless.
Anyways, I had fun making this, and am personally finding a lot of these enhancements useful.