The trees actually seeded at a very wrong place in case the property "Confinement" was not set: The area.x, area.y, area.w, area.h coordinates were specified as global coordinates, but were used as offset coordinates in PlaceVegetation.
This leads to the trees seeding underground, too, unfortunately.
The trees actually seeded at a very wrong place in case the property "Confinement" was not set: The area.x, area.y, area.w, area.h coordinates were specified as global coordinates, but were used as offset coordinates in PlaceVegetation.
This leads to the trees seeding underground, too, unfortunately.
Added a callback QueryRebuy(int for_player, object base) in the vendor library. If an object that will be sold returns true in that function then the object will not be added to the base material of the selling player.
Currently the only objects that are sellable are Diamond, GoldBar, Nugget, Ruby. They cannot be rebought, just as in the previous implementation.
The existing Seed() places plants with a random chance. This makes testing the placement tiresome, so the actual placing part was moved to the new function DoSeed().
The functionality of taking construction materials from a clonk and lorries was extracted to a separate function and moved from the constructor to the construction site. This is a little bit of an esthetic decision, but it is also useful for my project that has a spacebar-interaction which takes construction materials from the clonk without the need to open the inventory menu.
In certain overloads of the object I want to be able to not eject contents, or eject only certain objects. The default behaviour of ejecting ALL contents whenever someone buys something is annoying in certain structures, such as a marketplace.
Conflicts will be merged in the next commit:
planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/PipeLine.ocd/Script.c
planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/Script.c
Added tests for adding to the queue and clearing the queue. The other tests are dummies for now. Found out that the parameter 'abort' in ClearQueue() was never used.
This special case is a relic, because I do not know whether this is actually a use case that is required in a scenario. All unit tests in the producers test pass now.
- Crosshair doesn't work with a dpad anymore. Supporting dpads adds
unnecessary complexity, as a gamepad user with dpad will never be
competitive with mouse users.
- Crosshair isn't bound to item usage anymore, but will always show
when the analog stick is outside of a deadzone.
Future planned feature: Also use the actual strength to allow
distance input in addition to direction. This is used heavily by
Knüppeln.c4s.
The callback happens in every call to MergeWithStacksIn() now, instead of RejectEntrance(). Otherwise the following use case does not work: Liquid enters crew/building and fills the contained barrels. Added a unit test for that use case. Stackable unit tests still pass.
The function RejectEntrance() has two more callbacks to the object it should enter:
- CollectFromStack(object stack): The object can grab items from the stack, before the stack tries to merge with stacks in the object. This is necessary for barrels, so that a large liquid stack can fill an empty barrel.
- RejectStack(object stack): This is called after the stack is merged. Currently, the stack merging counts as handled only if the stack is removed. This callback allows the object to still reject the stack, for example if it accepts only one item, such as the barrel does.
The previous name suggested that the object actually gets put into another object. In fact it merges the stack count with other stacks, and it does not only try to (and reverts the state if it fails), but it actually changes other objects even if the function returns false.
This got removed by accidet (checking if the object was added to another stack seemed logical). However, this whole function does not really make sense. It returns true if the object got removed only. That means that the object would not enter the other object anyway.
Removed the UpdateStackDisplay(), because that happens in TryAddToStack() if the count changes, anyway.
The part where the stack count is reduced behaves the same as DoStackCount(); The stack display is updated in SetStackCount()/DoStackCount() respectively, so that line can be removed.
Added parameter to 'GetFuelAmount' that specified how much fuel is requested from this object. Oil is now fuel and only the needed amount is removed instead of removing the entire stack when a producer requests fuel.
This was used inconsistently and without regard to correctness, so it is better removed altogether. In case of incomplete objects, the incomplete object always returns the reduced amount.
The liquid objects cannot be converted from one to another. The fuel object will be removed again, it does not make sense that "burnt fuel" can be transferred from one object to another.
Previously, sharing the logic made sense, because both objects used variables to store the liquid. Now, the liquid container stores liquid in an object - this is not desirable in the pump because it would create and remove objects for no good reason (only so that it has a virtual liquid storage) every time it pumps. Consequently, liquid objects cannot enter a pump anymore.
Unit test 3 still fails, because the functions are not runtime overloadable. Test 12 fails, because liquid transfer does not work correctly yet. This fill be fixed in the next checkin.
Added debug logging, this has to be removed again later.
Unfortunately, now the object is not actually transferred, but removed, and a new one is created or an existing one is filled in the liquid container. The logic could use a rework actually, because everything was more clear when the container stored things in variables.
The special handling of the stackable library was moved from the interaction menu to that library. The reasoning behind this is that the menu should not have to know each and every object, but the objects should tell the menu how they are displayed.
Liquids are displayed by their liquid count now. It would be even better, if the max. capacity would be displayed without having to hover the description field.
The liquid container now stores liquid objects, instead of volume and liquid type. Liquid objects can have be of a specific type, such as Liquid_Water, Liquid_Oil, etc..., but they can also just stay Library_Liquid for other liquids.
The liquid container logic has become more complex now, but still works as before. Transferring liquids to other objects may still need some improvements:
- at the moment, transferring liquids between liquid containers is possible
- maybe liquids objects, such as oil, can enter a liquid container while another liquid is in that container already - will need a unit test for that
- transferring liquid from a liquid container to a structure or crew member should be possible (but is not yet), if the target is not a liquid container but contains liquid containers
The steam engine can burn oil as fuel now. Added test to power system unit test. Still needs support for actually getting oil into the engine.
Fixed a bug in LiquidContainer that would return no liquid if the entire contents are removed. Added unit test for said bug.
Fixed overspilling of connected liquid containers. Pump no longer counts as a liquid container/tank, so that it still spills liquid if no drain is connected.
Now it is possible to connect lines from a pump to the steam engine. This is achieved by the steam engine being a liquid tank. It did not seem good to allow connection from pumps to all liquid containers (i.e. barrels). A liquid tank is also a liquid container, they share the same interface, but it is also a structure.
It is not yet possible to fill the steam engine with any liquid though, because it is not defined what kind of liquid it accepts. This will be oil in the future. Furthermore, the behaviour when the pump adds incompatible liquid is not defined yet.
Added a new library for liquid containers that is based on the original barrel script.
Library_LiquidContainer
- Extracted the interface from the barrel. The function names and argument types are not final yet.
- Fixed an inconsistency in the script: There were two ways of determining whether a barrel is suited
for a material. Either by name, or material index.
- renamed argument names to "liquid_name" for liquids, "amount" for quantities, so that the code is more easily understandable
- replaced comparison 'fill level > 0' with 'is not empty?'
- moved storage variables to a local proplist, so that names do not clash
- Ordered the methods by application and documented each section
Barrel:
- The original barrel functions delegate to Library_LiquidContainer-functions now, so that the original functionality is not disturbed. Obsolete functions are marked with "TODO: deprecated".
- Moved barrel value change to the update function
- Moved hit sound effect to separate function
- Replaced uses of the magic number '3' with a runtime-overloadable call to GetBarrelIntakeY()
- Replaced comparison 'fill level > 0' with 'is not empty?'
MetalBarrel:
- Adjusted the hit function. The difference between this and the normal barrel is the hit sound and material position. These should be constants or functions, instead of magic numbers
- Moved hit sound effect to separate function
- Removed the Hit()-function, because the hit sound is played in a separate function now
- With this change the y-offset of the barrel checking for other liquids on a hit is now 3 instead of 7. This should be ok, because the barrels have the same dimensions, it seemed strange that they would have different offsets
..because the library wasn't actually USING the holding callback at all. And it had/has its own CON_Aim hackery anyway. No need for the control-library internal CON_Aim stuff then (I could imagine this might just lead to issues at some point).
Otherwise the situation could arise where you used a ControlUseStart object (the wallkit) but noholdingcallbacks was still set to true (because e.g. you used a hammer before). Then you would not be able to move the preview.
This is described in a comment to the referenced bug.
"menu" is an error prone name in one of the most frequently used/overloaded objects of the planet. Actually, there was a bug in some other thing which disappeared now. So I guess something, somewhere uses the name "menu", too.
Anyway, this is more consistent (because the other control stuff is in this.control, too) and less error prone. So it's a good change regardless of whether it actually fixes an existing bug.
Structures can use the definition call ConstructionPreview(Previewer Object, Overlay, Direction) to add any overlay to the previewer. It will be coloured accordingly.
Extracted the buy menu of the flagpole to a library, so that other objects can implement a buy menu without having to duplicate the code. An overview of the changes follows:
Library_Base:
- Moved auto-sell functionality to Library_Vendor
- Moved buy and sell functionality to Library_Vendor
- Removed the old engine menu for buying and selling
Library_Vendor:
- Added proplist for accessing local variables, avoiding variable clashes
- Added interfaces GetBuyValue, GetBuyableItems, GetBuyableAmount, ChangeBuyableAmount, GetSellValue
- Changed DoBuy: it uses the interface functions, instead of hardcoded base material
- Changed / merged the existing sell functionality and the flagpole sell functionality in DoSell:
* does not sell items if QueryOnSell returns true
* sell sound only audible to seller
* the sold object tries selling its contents first (for example a bow, if it ever were sellable. This may not hold in the settlement games, but adventures would allow it)
* the sold object ejects any contents before it is removed. These are usually unsellable objects. Previously they would just be removed together with the object. It has to be tested whether this places the items on the ground or at the center of the sold object
* removed the "sell all" functionality on right-click for the moment.
- Still has some functions from the old base selling: CanStack and GetSellableContents, for the auto-sell functionality
- Fixed a logical error in AllowBuyMenuEntries
- Distinguish between buyer/seller and payer more, so that the logic can easily be changed in one line later
- Allow for runtime overloads of interface functions
- Changed inconsistent variable naming to a more consistent one
- Added namespaces to all sounds, the "UnCash" sound still does not exist
- Added localization strings for insufficient wealth
- Fixed property name error (missing 'e')
- Buy menu is active by default
Flagpole:
- Replaced the custom sell functionality (how many of these do we have actually??) with the sell functionality from Library_Vendor
- Buying menu is allowed if the rule is active
System.ocg/Object.c
- global functions Buy and Sell ask the target if it is a vendor, instead of whether it is a base, and do the callback there.
- renamed the argument so that it is no longer called "base", but "vendor"
This is solved via another entry in the production menu (below the products), which is updated by an effect, that is being told the menu ID/target by the interaction menu through a callback.
This setup allows for very intrusive changes to the interaction menu with only few lines of code!
The players have no notion about the midpoint of an object and are thus confused when clearly standing in front of something and not being able to interact with it.
(Yes that happened in a Let's Play and yes, that's why the interaction menu also uses Find_AtRect.)
Because it's an interaction. It should use the interaction interface and not some self-made hack. Previously, setting down a carry heavy object would always be executed even if aborted with Space+S.
We are looking for free objects. So for OCF_InFree and not for Not(OCF_InFree). Now Clonks are e.g. unstuck when the landscape adjusts to a construction site.
A single player now receives four times more wave bounty than before, scaling up to four players. It's still challenging but I believe now doable.
Enemies should no longer jump off airships when being shot at.
Fixed a typo in the airship appendto script.
Fixed a possible null pointer when changing weapons.
The player interface is now similar to how picking up works. This should increase acceptance. Also it was pretty fucked up before. The action bar is gone.
The script logic is now outsourced into a new library similar to the other stuff.
Objects can overload the selector for the new interaction (see "call elevator case").
Additional issues hit and resolved when working on this:
Shifting a cursor did not cancel certain actions (and there was no callback for that). This is now solved by adding two new callbacks.
Issues hit and not resolved:
Certain interactions (calling an elevator case, flipping a construction) are in some control library. They should be in the respective objects (and shown via callbacks etc.). Meh.
The internal interface (declaring interactions etc) has a few places where proplists are just translated because the properties are called differently. This is also a fuckup (i.e. a.interaction_object = b.Object) where the properties should just have been called the same in all places from the beginning.
The name "Action Bar" is pretty misleading now as it is no bar. But that's not something visible to the players. todo: cleanup.
..by not using proplist access too much. I noticed the Playground would start lagging (debug build) and the profiler told me it was the mosquitos.
Before, 83% of the time in Mosquito::Activity was spent in MoveToTarget. After the change, only around 70% (multiple runs).
Is this a sensible way to measure the change?
Previous:
[14:30:22] 00186ms Mosquito.Activity
[14:30:22] 00155ms Mosquito.MoveToTarget
Afterwards:
[14:37:37] 00238ms Mosquito.Activity
[14:37:37] 00172ms Mosquito.MoveToTarget
This doesn't work for intros, though, because they use simple messages. We should unify the systems to only have one dialogue system that uses new-style-menus and implement required features in those menus..
After some testing, the text turned out to be the worse solution. At least Sven complained that the text was split into two lines on his resolution from 1997.
Objects that prevent interaction just in some situations (hostility, dead Clonks, ..) should always be shown in the interaction menu (because otherwise players might suspect bugs) and TELL the player WHY they want no interaction.
For that, they might need to specify own error messages.
Known issues:
* The "OnOpen" callback is done even if interaction is disallowed, however just simply removing the callback might not be sufficient, because we might get a callback disbalance if objects change their attitude while the menu is opened and the menu is closed again.
* Some objects (which should) do not include the Library_Ownable. However, we have no base melees atm and since this might introduce new errors, postpone it to 8.0.
This can be helpful to see why the observed behavior is triggered in some cases (e.g. why a fish swims straight into a wall (hint: because the wall was left AND right)).
DumpCache() can be used like so:
var brain = FuzzyLogic->Init();
// ..do stuff
brain->DumpCache();
When CheckAllComponentsForProduct returned true, but the item could still not be produced (due to missing water etc.), Produce would fail but the queue would not be cycled.
Now CheckAllComponentsForProduct is gone (why was it there anyway?) and if anything happens in Produce, the queue is cycled.
This means that you start a roll currently with walking left/right and tapping [down]. OR falling a great height and just holding left/right when landing. When you let go of left/right, you will instantly walk again. This reduces the possibility of the players rolling into an abyss.
The count was displayed twice in certain situations: in the picture AND as a number.
Now the responsibility for displaying the count is solely on the menus' side. The objects only show an additional overlay when their count is infinite (to not display an arbitrary "50" there).
Objects now stack iff CanBeStackedWith returns true. The displayed symbol is now the first object of the stack (instead of the definition).
Also fixed barrel to not overwrite the custom name just after setting it.
Steps to reproduce: put shovel on ground. take dynamite. stand on shovel. aim below you. leftclick. leftlick. => dynamite is planted AND shovel is collected.
Added interaction icon to help knowing when interaction is possible.
Limited crew portraits and information to two clonks.
Added additional warnings texts for further clonks (crew count > 2).
Moved inventory from bottom to top.
This seems to be the intuition of every living being ever to have touched Clonk. You can now collect items that you click on (given that they are in range). You will however also just collect the next-best item when either not clicking on anything specific or when the item is out of range.
That means that you can use left-click as a shortcut to hitting [shift].
This is mainly to get rid of IsContainerEx, because wtf.
The only reason why the categories were restricted was to prevent HasExtraSlot-objets from being found. Some C4D_Objects (or with wrong category in general) wanted to be found however. They are now found just like that.. like it was supposed to be.
RejectCollect is not called on CreateContents or other forced entry methods but should still cause the lantern to attach. So move any side-effects to Collection2 instead of direct RejectCollect.
The lantern dummy had Timer=1 and wasn't doing anything. Use a simple overlay instead.
Note that interaction menus still show the lantern always with off-material. But that's a bug in the interaction menu.
The clonk opening the menu should always have higher priority so the clonk is predictably selected on the left side even if standing behind e.g. a crate.
Other clonks should be behind because interaction with them is rare but having your fellow players stand in front of a building is very common. Allies also tend to run in front just when you opened that menu.
The check for initial selection was broken because GetIndexOf does not return nil when the index is not found. It returns -1.
The previously intended logic (that never worked) of selecting in direction of the clonk view first may sound intuitive, but is weird in practice when you're standing just on top of an object that is 1px behind you and it selects an item very far away instead. It's particularly counter-intuitive when picking up objects out of the earth while scaling.
Previously, the em <-> pixels conversion was a hardcoded value. Now the GUI scales with the font size that can be selected in the options.
Sadly, all scales were off since the hardcoded value was too low.
You can now intentionally collect objects that are stuck. Player-friendliness over everything! Losing an object in a basement had been the number 1 reason for suicides in Clonk.