Improve readability by adding appropriate parentheses and braces, and fixing misleading/confusing whitespace. Extract SolidMask removal to a function since it's used in several places.
Previously, the error message was only silenced for openclonk-server,
but appeared for openclonk if compiled without sounds.
Possible side effect: no local sounds will play if the global Sound.ocg
cannot be loaded. I don't think this is something we should support.
The old LineFeed constant caused problems with Qt. Using \n directly is
easier and I don't think there's a reason left to use \r\n anyways.
We've always converted the files in the repository. Nowadays, even
notepad.exe works with unix file endings.
The parser was only checking that the passed setting matched the
beginning of the expected keyword, instead of checking for the full
length. This way, users could write "#warning e" instead of the
expected "#warning enable" and still have it work.
When no parameter followed the "#warning" pragma, because the end
iterator would be located before the begin iterator, basic_string's
constructor would throw std::length_error. Check for this case
beforehand so we can throw the expected C4ParseError instead.
Switching to random teams would remove all teams but the first two on
the host, but not on the clients. With this fix, the extra teams are
removed on the clients as well. This fixes a desync when using
GetTeamCount() in a sync-relevant way.
operator void* is a quick and dirty workaround for the lack of
explicit operator bool in old C++ standards. Since we can use
explicit operator bool now, we don't need the operator void*
anymore.
Incidentally, that operator also allowed C4Set to equality compare
C4Property entries, which is unintuitive. Replace it with an
explicit specialization of C4Set::Equals.
C4Set used to set its removed elements to nullptr. This requires
some special handling from non-pointer entries like C4Property.
Overwriting the element with a zero-initialized one removes this
requirement, leading to improved type safety on the part of
C4Property.
CMake before 3.7 didn't properly pass the standard selection flags
to try_compile. Wrap try_compile on old CMake versions so that the
flag gets passed.
The C++ standard doesn't require us to stuff multiple statements
onto the same line, so we should avoid this for readability reasons.
This is especially true if one of the statements is controlled and
others aren't.
Some code here was indented like it still belonged to the loop
above, but never did, and was never intended to. This is an
excellent argument for why braces are good, especially for
statements which span more than one line.
We're not using the <locale.h> header anywhere besides including it
for no purpose, so we can drop the test (and the inclusion).
Additionally, the header is part of standard C++.
CMake 3.5.1 is the version that ships with Ubuntu 16.04 LTS. Ubuntu
14.04 LTS was already unsupported by our build, so we don't need to
worry about that.
Not sure about air pipes yet, those should theoretically be either
source or drain, instead of a separate connection category?
See also:
https://bugs.openclonk.org/view.php?id=1871
The library did not depend on the Library_LiquidContainer script at all,
removed that include and added it to the previous includers.
Removed the IsLiquidTank() identifier, because it was unused.
Smoke used to fly higher with gravity 40 than with gravity 10. Fixed
this by using a start value. At default gravity, light smoke will fly
rise a little higher now, and heavy smoke behaves the same.
With higher gravity the smoke may fall to the ground now.
The production cost method returns an array of material cost arrays, but
their format has changed. Instead of
[<default resource>, <cost>, <substitute(s)>]
it now returns an array of proplists
[{Resource = optionA, Amount = costA}, {Resource = optionB, Amount =
costB}]
so that there are fewer cases to keep in mind: No "are there
substitutes?", but you can simply check all variants and pick the best.
This also allows different substitutions, for example "2 earth or 3
sand" is now possible.
It seems that the default structures have the entrance close to the
offset, so that there is an overlap and can_be_entered is true even
inside the structure.
In my case the structure offset and entrance area do not overlap, so you
could unfortunately not leave the structure.
AppVeyor occasionally updates platform images without really
versioning them, so in order to have a higher chance of not being
broken by those, we'll just use 5.11 instead of specifying 5.11.1
explicitly.
Qt's moc generates another source file that includes this header without
including C4Include.h first. The generates source file thus doesn't
compile. It is unclear to me why this isn't an issue with our current
build setup (it is an issue with a meson-based build).
The branch information is necessary for upcoming automatically-updating
snapshots. For Travis, cmake will also pick up the branch name from the
C4REVISION_BRANCH environment variable.
Debian packages older/newer gcc versions with executables named like
gcc-5, gcc-ar-5. The previous implementation did not handle this
correctly, breaking LTO-enabled linking.
As the timer tends to run more than once, you'd also very likely get the
error more than once. The timer also often determines the effect
lifetime, making a broken effect live forever.
This was especially annoying with one-off Schedule() invokations
that wouldn't even stop throwing errors after finishing the
designated number of repeats. Although fixing just that script
function would have been possible, I believe that a more general
solution for all effects is useful.
We already notified the user on warning/error that the mistake
happened in a different script than the one we were currently
compiing. It's not too difficult to figure out whether that other
script was added due to an #include or an #appendto directive, so we
can just show the user which one it is.
We also don't show warnings in #include'd scripts anymore, since
they get compiled individually anyway and all warnings will show up
there. This way we don't duplicate warnings several times.
When we introduce block scoping, using variables declared in a more
narrow scope from a block with wider scope will fail. Warn about
these so people can avoid it and fix their code.
While I do not agree with the idea of using straight assignments in
the condition of a for loop, people are divided on the argument and
lots of old code uses it.
When cross-compiling c4group should be build for the host
machine before building OpenClonk for the target.
Without C4GROUP_TOOL_ONLY option, we have to build OpenClonk
for the host.
C4GROUP_TOOL_ONLY allow to build only c4group tool for the
host.
Signed-off-by: Romain Naour <romain.naour@gmail.com>
---
With this patch I can build OpenClonk with Buildroot.
While cross-compiling, it is easier to find a binary
from the patch using FIND_PROGRAM instead of using
a cmake file.
Try to find c4group native tool with FIND_PROGRAM and
fallback to the cmake file if c4group is not found.
Signed-off-by: Romain Naour <romain.naour@gmail.com>
As reported by [1], some distributions use shared libraries as
default preset in CMake.
Without explicitely linking statically libmisc and libc4script,
we have the following link issue:
[...]/host/bin/x86_64-linux-g++ --sysroot=[...]sysroot
-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os
-std=gnu++14 -Wall -Wextra -Wredundant-decls -Wendif-labels
-Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Winit-self
-Wsign-promo -Wno-reorder -Wno-unused-parameter -Wnon-virtual-dtor
-Woverloaded-virtual -DNDEBUG
-rdynamic CMakeFiles/c4group.dir/src/c4group/C4GroupMain.cpp.o
-o c4group
-Wl,-rpath,[...]/build/openclonk-7.0:
liblibmisc.so -lz -lpthread -lrt
liblibmisc.so : référence indéfinie vers « C4LangStringTable::Translate(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const »
liblibmisc.so : référence indéfinie vers « C4LangStringTable::system_string_table »
[1] https://github.com/openclonk/openclonk/pull/26
While at it, build libopenclonk statically since libopenclonk is not
installed by the CMake build system.
Signed-off-by: Romain Naour <romain.naour@gmail.com>
FatalError(Format(...)) was necessary previously. Actually it seems not
like a huge thing, but being able to format the string directly in
FatalError is a lot more convenient.
Renamed and documented the former function SetNextMission. Added a script wrapper for the old function that issues a warning. Renaming is based on the fact that the docu speaks of scenarios, and other functions, such as GainScenarioAchievement already use this terminology
There are currently multiple multi-round scenarios in development that
all copy most of HotIce's >500-line scenario script for the multi-round
logic. This commit isolates that logic in a goal with an easy-to-use
interface.
This is a rather chaotic commit and does not solve all problems of network creation yet, but is an improvement over the old system where deletion of a cable line would fail the network. However, we probably need a cleaner method to construct a network properly.
Bit 3 (C4MatOv_Monochrome) was removed in fc5c38468 ("Material: Remove
color field, use textures as is", 2009), but was still mentioned in the
documentation.
This introduces a new diagnostic (suspicious_assignment) which
issues when an the compiler finds an assignment either where a
condition is expected or as the parameter to return.
The actual release names dropped the 5.x.x scheme long ago, so there is
no reason to keep it in the docs. It's extra confusing there because the
version is given as a two-part version (e.g. 5.1) most of the time, so
it looks like everything happened in OC 5.x, even though the change was
actually in OC x.0.
While amd64 always supports the SSE2 instruction set extension,
other architectures don't (including 32 bit x86). For the platforms
that don't, we'll use the reference C implementation by default, but
allow users to override it with the BLAKE2_USE_SSE2 option.
While amd64 always supports the SSE2 instruction set extension,
other architectures don't (including 32 bit x86). For the platforms
that don't, we'll use the reference C implementation by default, but
allow users to override it with the BLAKE2_USE_SSE2 option.
Not recommended for 8.1, because there are semantic changes: The club can now also hit targets (IsProjectileTarget) while before it could only hit OCF_Alive and C4D_Object. It's similar to the sword now.
Oh, and before it could also not hit livings that were stuck.
The crypto "library" only consists of a single function at the
moment because that's all that users have asked for so far. It is
also highly experimental. We will make an attempt to keep the public
interface (i.e. the interface provided by Library_Crypto.c) stable,
but it might still change if necessary. The internal interface
(provided via the global _Crypto proplist) is not for public
consumption and will probably change at some point.
GCC6 doesn't like getting some of its default include search paths
passed with the -isystem flag, and the devs seem unlikely to change
whatever they did back to before they broke it. Work around CMake
not dealing with it well either by figuring out the paths at
configure time and telling CMake about them so it can avoid adding
them superfluously.
In Tower of Despair, the scenario saves per-room progress in the
player files. Players win individual rooms, but never the whole
scenario. Consequently, they currently have to give up to make sure
they don't lose their progress. This is not intuitive at all. With the
new flag enabled, players will be saved even if the scenario is aborted.
- added a German translation of the GenericName field
- left out the "multiplayer" part, because OpenClonk is also a very fine single player game but this would make the German translation much too long...
Pressing Ctrl+S while on the Credits screen will save everything to
Credits.txt in the current working directory. This is only meant for
developers modifying the credits; the shortcut isn't mentioned anywhere.
The values from the enums are converted to numbers a lot, so using an enum class would be counter-productive.
Having 'left' in the global namespace appeared to be an actual problem with some Qt headers, according to Fulgen.
Foundry is now flippable. SteamEngine is not yet flippable due to collection zone (could use similar solution as foundry).
Pump is not yet flippable, because I don't want to test the bazillion combinations of states of the pump now - maybe after a release.
- Allow configuring keyboard keys with modifier keys
- Allow using Alt as a key in game on linux
(I'm still puzzled why only Ctrl and Shift where implemented in so many places)
- Adjust the deserializer and PlayerControls.txt to match the serializer for mouse keys
- Refactor C4PlayerControl::DoMouseInput a little bit
- Try to fix the Mac build (attempt 1)
- Fix a bug in C4KeyCodeEx::CompileFunc where it set an incorrect KeyComboItem::sKeyName
- Fix(?) StdCompilerConfigRead not doing anything on NoSeparator
PauseUse can be called between ControlUseStart and ControlUseStop/Cancel. In this case ControlUseStop set aim_stop=1 but didn't actually stop reloading (which is somewhat fine). However, this led to PauseUse being called when e.g. tumbling or climbing.
And this again would lead to CON_Use being reissued even though the mouse button was not held down, leading to the Clonk being in aim mode.
The functional change here is that you will not continue reloading after tumbling/climbing when you are not holding down CON_Use anymore, which is consistent with other stuff.
Related to #1970 and 5fc07df757
This replaces the very hacky implementation just for the dynamite with a more general solution (and e.g. also works with the grenade launcher).
When the damage times the total component value was much lower compared to the total HitPoints (e.g. with basements), the damage could sometimes not be repaired.
This is fixed now.
var a = {B=1}; var b = new a {B=1}; would include "B" twice in the list of properties.
This lead to an actual issue when calculating component value for repairing buildings
The GIDL is now C4D_Living and C4D_StaticBack, preventing it from moving. At first I thought that adding an underground vertex would be sufficient, but that still made the idol move/shake when hit.
The old icon overlay was behind the numbers in the inventory menu anyway. Now the object uses a bar similar to loam. And it also updates its description.
When turning empty, the (new) barrel is also no longer play-colored inside.
The powder barrel could of course just use actual gunpowder and be an extra-slot item (like the bow / dynamite box / etc.).
This reverts commit 8698aa25cf.
Tackling #1970. The implementation in the reverted commit was incorrect (i.e. only one out of two "GetStackCount" were replaced with GetInteractionMenuAmount, leading to weird behaviour). If you want to replace it, please do it in a way that no call to IsInfiniteStack will be required. And this hack would probably require so much more bloat code that nothing would be gained (i.e. what happens when you put two infinite arrow stacks in one container?).
The bug report complains about the "display stopping at 999" *in some situations*, which was due to Stackable_Max_Display_Count. It's gone now. And that it was not limited to 999 in all situations (like the code would have suggested) is probably due to the things I described above.
# Conflicts:
# planet/Objects.ocd/Libraries.ocd/LiquidControl.ocd/Liquid.ocd/Script.c
# planet/Objects.ocd/Libraries.ocd/Stackable.ocd/Script.c
The shield and bow both use fx.aim_weapon, but the ranged weapons AI thinks that a shield works the same way as a bow and tries to fire it - in order to prevent this, the AI now also checks whether the equipped item is a IsRangedWeapon. This _could_ have an impact on the vehicle AI, but the unit test worked fine.
While saving the landscape, solid masks are temporarily removed. This
did not work for half solid masks, resulting in permanent solid masks
after restoring the save game.
Instead, the lorry asks a container whether it should eject its contents. This is done via the callback LorryEjectionOnEntrance(object lorry) in the object that is being entered.
The old callback NoLorryEjection(object lorry) is obsolete.
Removing liquid collection from the lorry is a side effect, but it is not bad. The lorry behavior was weird anyway, because you could for example put lava and wood in it, without the wood burning etc.
The unit test does not really pass for now (it never did before, because it is not finished yet and used for testing the different transfer function behavior only)
Most scancodes are two hex digits long, e.g. "$24" (J). However, there
are also a couple keys like Backspace ("$e") and Escape ("$1") with a
single-digit scancode. These previously weren't restored correctly.
The matching had a few issues:
Items with the same symbol were supposed to be stacked, but the "symbol" changed from ID to object at some point. So same-type objects were no longer correctly matched.
Items with different text (e.g. amount) but everything else the same should be stacked. But simple proplist equality is obviously not sufficient to determine whether the contents of the proplist changed.
The order of the items is generally more stable now. I hope this doesn't introduce other issues.
It was no longer used. It's also just a stretched dot. Consider using an actual stretched dot instead (i.e. round GFX and Stretch = XYZ).
The sprite was also a little unclean.
Yes, someone just had the "slow-mo" switch on. I also replaced the usage of the "RaindropSmall" particle (which was a stretched dot) with an actual stretched dot.
This does not change behavior at all, as nil-objects were later ignored in the check. Now the check is not even executed.
This does make it more likely that refactoring will keep the ignoring behaviour in place, though.
Loosely related to PR #61 - has nothing to do with the solution, though.
Improved the barrel fuse effect in two ways:
1) The fuse is not at the center of the poweder keg anymore, making it more prominent
2) When carried by a clonk the effect is at the keg instead of the clonk center
I'm not sure how exactly that issue happens, but in the attached video
it looks like C4D_StaticBack was accidentally set again. As the XOR
operation can do that, I'm changing it to always set the C4D_StaticBack
bit to 0.
The old code did some obviously wrong things like calling functions
expecting relative coordinates with GetX()/GetY(). It also sometimes ran
into an infinite loop in Cloud->Place(). I fixed those issues and
cleaned up the rest to be nicer, hopefully without changing
functionality.
The previous behaviour of only checking the background broke existing
maps and triggered some (performance?) bug in the mass mover. It is
still available by setting AutoScanSideOpen=2, for symmetry with
Top/BottomOpen.
In a text line containing <c ff0000>markup</c>, C4LogBuf would
occasionally split the line after <c, producing broken markup.
Additonally, markup spanning multiple lines would always stop at the end
of the first line.
With this commit, lines are never broken within tags and any unclosed
tags are repeated on the following line.
- Each packet has a version field.
- Clients connecting to the netpuncher always send a request packet.
This allows the netpuncher to react differently depending on the
client's version.
- Encode packets as binary instead of ASCII. This allows adding fields
while maintaining compatibility.
With my fix from 9eb2478b2 ("C4NetIOUDP: Fix timeout during non-MC
connection"), C4NetIOUDP would send data packets to the master server
before the ConnOK packet. The server would then discard these data
packets, resulting in a one-second delay until retransmission.
The "normal" connection process is a three-way handshake (Conn->,
<-Conn, ConnOK->). When establishing a multicast connection, this
handshake is repeated via the MC address. However, the code always
expected that second handshake to happen and thus ran into a timeout on
the client in the non-MC case, repeating the handshake a second time. In
the end, it usually still worked as the server supports reconnecting,
but packets may be lost in the process.
Instead of continuing to swing forward the Clonk stops immediately while
hangling. Additionally the hangle animation keeps on playing with a
short delay before it changes to the hanging animation, so that the
motion looks nice if you move a short distance only.
A fireproof container shields all contents from incendiary material (lava mainly). Structures can now be submerged in lava and the contents will not burn up.
Before commit 5a652f23e ("Fix missing C4PXSSystem::Clear
implementation"), ChristmasIce would keep all snow PXS between scenario
section changes. That looked pretty neat, so I'm introducing this script
function to allow properly implementing it.
The old system allocated chunks of PXS on demand. I can't think of a
good reason to do this.
The savegame format changes slightly to not require saving full chunks,
however old savegames will still load fine (invalid PXS within chunks
are moved out during the next Execute() call).
Savegames with a foreground material diff but no background material
diff would not apply the foreground diff at all. As the background
material rarely changes, this broke runtime joining for most scenarios.
Objects will be destroyed after local HitPoints has been reached in damage taken. Objects will explode into little burning bits, just like it is with lorries.
Increased burn time (140 frames) for: axe, bucket, grapple bow, hammer, pickaxe, shovel, sickle. So useful items will burn a little bit longer.
Coal will burn for 245 frames and then just burst into ashes and not change into a Burned Object.
Objects will be incinerated by incendiary material (which before was only possible by using ContactIncinerate).
local MaterialIncinerate = true; - object will burn in lava not from other burning objects.
When ignited, the object will burn for a fixed time (BurnTime property, default is 70 frames) with no detriment to its function.
After that time, the object will change to a 'Burned Object', no longer useful for anything.
All item can now define substitute components like this:
public func GetSubstituteComponent(id component)
{
if (component == Rock) // Rock is in the regular components
return Metal; // Rock can be replaced by Metal, amount is the same
if (component == Wood) // Wood is in the regular components
return [Cloth, Wipf]; // Wood can be replaced by either Cloth or Wipf, amount is the same
}
Many functions in System.ocg have proper documentation, but not next to
the code. When changing these functions, it is easy to forget updating
the docs. Nobody likes outdated documentation!
Linked flag changing now always updates all networks (which is not very
hard on the performance), special treatment for neutral network will be
removed with the next commit.
Imagine lhs being 0 and rhs being more than int32_t can handle. And then imagine subtracting them and casting them to int32_t.
That's what happened e.g. in void C4ShaderCall::Start() when ScriptShader.LastUpdate was 0. This caused the shaders to reload every frame;
at least when in the main menu. This lead to serious lagging (of the cursor) for me.
Note that the subtraction operator in C4TimeMilliseconds.cpp has a similar issue. This might need a fix or at least high awareness by users. Maybe an assert or something.
PS: Who thought that doing the comparison with a subtraction was a good idea? This is not assembler :I
The install target is used both for manual installation and for
packaging. Updating the packager's MIME cache isn't very useful. Show a
message instead which reminds both packagers and regular users to run
the command.
Can place items in the gold statue hands. In the future, it might be
actual items that get displayed correctly in the hands by themselves
(maybe I have to tinker with the model here, unless we want to have
custom transformation callbacks for every item).
Made the statue not movable, so there is no need to make it stuck in the
ground.
Other scenarios do not need an adjustment, because they use
CreateObjectAbove(), so the positions will be OK (tested with 3
scenarios).
Certain packs/objects may want to restrict your ability to roll. The
parameter that distinguishes between rolling from a fall and rolling
while running is helpful here.
Added callback OnNoHitPointsRemaining() that is called if whenever the
structure is about to be removed because it took too much damage. Should
the callback return true, then the damage counts as handled and the
structure will not be removed.
Having the ctor defaulted confuses MSVC 2015 and makes it not use the
templated ctor below even for calls with a parameter list,
thus skipping required initialization.
This fixes a slowdown in scenario selection when some of the dependency folders (e.g. qt) are searched for scenarios.
Should also fix a bug where music is loaded from the exe path instead of planet/ if present
Showing the definition means that objects can not modify their display in the extra-slot. E.g. the arrows would always show their "full" state. Now the arrow count is correctly displayed in the extra-slot.
The AI was split up into a basic controller object that contains just the AI control effect and basic logic. The other components should work individually, and the final implementation of the AI can import these components individually.
Fixed AI catapults, so that they now fire even if the clonk has no items in the inventory.
Merged from gitMarky/openclonk, branch ai_backport.
Another possible option was a parameter for the log level, but I decided against it, because differently named functions feel better than a string constant as a parameter.. Removed some annoying log outputs that I added before.
Any suggestions for the function names are welcome, because I am not quite happy with the names yet. The distinction between normal output and warning is maybe not even necessary.
The problem was in AI_TargetFinding, line 18: The clonk that has a vehicle, but not any contents, will never find any attack targets. The vehicle is saved as fx.weapon, so if the clonk has a weapon it asks that weapon first whether it is suitable, and only if not it consults the inventory.
Will streamline the two different functions later on. The difference is, that one function issues a warning, while the other merely provides information. Logging calls in components have to be called failsafe, because the cannot rely on the actual AI implementation including AI_Debugging.
This helps me understand why the catapult in AI test #7 does not fire. The solution is very interesting: The AI executes the idle strategy as long as it has no contents. After giving contents to the AI it executes the catapult strategy.
This usually happens in the following case from ClonkControl.ocd/Script.c:
// Release commands are always forwarded even if contents is 0, in case we
// need to cancel use of an object that left inventory
if (contents || (status == CONS_Up && GetUsedObject()))
{
if (ControlUse2Script(ctrl, x, y, strength, repeat, status, contents))
return true;
}
It could also be necessary that, instead of contents, either "this", or GetUsedObject() should be passed. Not sure which one was intended.
RootSurface() does not yield good results for all objects, so I think the function should have a parameter for movement range. Re-declarated the variable "i" in the second if-block; I always thought we had scoped variables, it surprises me that the previous version worked.
A follow-up on a previous PR GH-41. The discussion in the forum can be
viewed at http://forum.openclonk.org/topic_show.pl?pid=33086.
Run clang-tidy (without auto, pass-by-value and using checks) to fix the
header files not modified in the previous PR.
Summary of the changes:
- C++11 member initialization.
- nullptr instead of 0 for pointers.
- override for functions declared virtual in base class.
- default trivial special member functions
Consolidate the include statements scattered across the code in accordance
with this comment in C4Include.h. The advantages are listed in the same
comment.
Furthermore, it follows llvm-include-order which is the logical
extrapolation of the project's style guideline wherever possible
(C4Include.h being the most-frequent exception).
Summarizing the changes:
- Remove the files included in C4Include.h from all other files.
- Reorder the include directives in the cpp files
- C4Include.h
- main module header
- other headers (lexicographical order)
- Remove repeated include statements (easy to spot after sorting)
Tested the local Windows build and Travis builds succeeded for Linux.
Note: this was not all automated, the manual steps may have introduced
some errors in sorting.
Consolidate the include statements scattered across the code in accordance
with the comment in C4Include.h. The advantages are listed in the same
comment.
Furthermore, it follows llvm-include-order which is the logical
extrapolation of the project's style guideline wherever possible
(C4Include.h being the most-frequent exception).
Alut's pkg-config definition only adds the top-level include directory
containing the AL directory to the include paths. This works on most
platforms because OpenAL adds that AL directory. However, with nix,
these two directories are distinct and the build fails.
The hatch will automatically attach itself onto basements it finds around its center after it has been built. This makes it easier to use since people probably tend to forget combining the construction preview. Especially since basements are very slim. The hatch will reposition itself in order to attach. This means it is not right where the player placed it. The alternative would be to move the basement and I guess that even more unwanted.
The optimizer is going to remove dead code anyway, and has the
additional advantage of doing syntax checking, so the code won't
silently break when someone changes something.
Scenario parameters are useful in a script-only context (such as the one
mape uses). C4AchievementGraphics introduces a dependency on C4Surface
which isn't available in that context.
Previously, it would just use first pixel of the texture image. With our
current textures, this is a pretty bad approximation. For example,
firestone ends up yellow rather than red.
Additionally, this helps tools like mape/ocmapgen which do not load any
texture graphics but just set the texture's average color.
This also fixes the sky color which was previously overwritten.
Previously, the SReq packet would only be sent after receiving an
ID from the netpuncher. Instead, we can send the request as soon as the
C4NetIOUDP connection setup finishes.
All of our headers are designed to be included *after* C4Include.h,
which UnicodeHandlingTest.cpp didn't do, resulting in an ill-formed
program on some implementations.
With the IPv6 support, hosts now often list around 20 addresses.
However, most of these are local only and thus rarely result in a
successful connection. With the introduction of address sorting in
7d5596220 ("Sort addresses used for initial host connection",
2017-02-26), the connection succeeds with the first few addresses most
of the time.
This commit changes the initial connection process to start with only
the first four addresses. After 100 ms, it proceeds with the next four
addresses and so on. This should reduce the packet volume significantly
as the connection should be established after only one or two steps.
We may want to tweak the parameters if this turns out to make joining
slower in practise. In a "normal" setup, the first four addresses should
be the IPv6 privacy and stable addresses, and the next four addresses
should include the IPv4 addresses from masterserver and netpuncher.
100 ms are long enough to get an answer from the host and short enough
to not bother the player too much.
Instead of "Compiler" and "Decompiler", which make me look up what's
even going on each time I see them, use the standard terms "serializer"
and "deserializer".
C4Language is the only consumer of GetRelativePath. It cannot handle
arbitrarily sized paths, so discourage new code from using it by moving
it to C4Language.cpp.
Also remove the buffer size parameter which was always defaulted anyway
and use template parameter deduction to always get the correct size.
MSVC already knows where the Windows SDK is located, so we don't have to
replicate that logic in CMake (then get it wrong and link to an outdated
one).
With the addition of IPv6, some computers with lots of addresses are
reaching the old address limit of 20 addresses. We'll have to see how
this works out in practise. Maybe we'll have to do the connection in
stages to prevent sending out too many packets at once (like only
connecting to the first five addresses initially, then after a timeout
the next five, and so on).
Computers with multiple (possibly virtual) network adapters can have
tons of link-local fe80::/64 IPv6 addresses. Connections to those hosts
would run into a timeout before getting to public addresses behind the
link-local ones.
By sorting the address list, we can prioritize public IPv6 addresses if
supported by the client, then try IPv4 before working through the swamp
of link-local addresses.
TestHost can't check that SourceScripts is unmodified anymore because
C4ScriptHost contains a std::unique_ptr these days, so we can't copy
derived classes. Next best thing is just creating two instances of
TestHost and comparing those.
MSVC 2015 doesn't support raw strings that contain the sequence \"
(U+005C REVERSE SOLIDUS, U+0022 QUOTATION MARK) and fails to compile
with error C2017.
InitializePlayer() semantics differ in online and local games. In a
local game, InitializePlayers() is called before InitializePlayer(plr);
in an online game it's the other way around.
This also improves handling of players joining at runtime. Those
previously started at random positions.
Close GH-32
After GameOver(), the global function CollectStatistics() is called
which in turn calls CollectStats() on all definitions and the Scenario.
The results are collected into a proplist and sent to the masterserver
as JSON.
The intended purpose is to collect statistics like weapon kill counts
and evaluate them across all online games to improve balancing.
GTest usually only increments its part count per EXPECT_* call, which we
don't use in diagnostics tests, so all compilation failures would show
as part number 0.
Instead of declaring an error handler every time we run a subtest, we'll
just use a class member that we clear when we leave the scope of the
subtest.
The macro is a bit ugly but solves the issue with redeclaring the scope
guard.
Compilation without an associated ScriptHost happens in a call to eval,
in which case we'll fall back to the default warning settings (because
we don't have a location which we could get settings from).
Fixes#1891.
We don't benefit at all from privacy addresses as we're publishing all
local addresses in any case. By preferring stable addresses, we can
avoid reconnection issues after the preferred address changes.
This API is defined in RFC5014, but apparently only implemented in
Linux.
Yeah. Aul looks up function parameters before local variables when
trying to resolve an identifier. Usually this doesn't matter, but you'll
notice it if you have a local variable and a parameter with the same
name, because the variable should be initialized to nil yet you get the
value of the parameter.
This commit introduces a new Aul directive "#warning", which can be used
to enable or disable warnings for a particular piece of code.
"#warning enable" enables all warnings.
"#warning disable" disables all warnings.
"#warning enable empty_parameter_in_call" selectively enables one
specific warning while not affecting any other.
All warnings that used to be controlled by Developer.ExtraWarnings
remain disabled by default.
Aul will now emit a warning if you type something like
if (...); return true;
(note the semicolon right after the condition). It will also warn on an
empty 'else' branch. If you actually intended to have a no-op there, use
an empty block '{}'.
In contrast to getifaddrs(), /proc/net/if_inet6 allows filtering
deprecated privacy addresses. As these addresses generally won't be
useful for new connections, there's no reason to include them and they
only cause unnecessary connection attempts.
On Windows, we cannot resolve addresses using getaddrinfo() before
initializing Winsock. By storing the address as string, the address
parsed later on.
Forcing a static address does not work for IPv6 where everyone has
multiple addresses that change over time. For example, adding a new
connection would fail if the preferred privacy address changes during
a game.
On Linux, all IPv6 sockets are dual-stack per default; on Windows, they
are not. It's still a good idea to set the option on Linux as well as
the default value can be changed.
When connecting via TCP, C4NetIO still creates IPv4 sockets, so no dual
stack option is required there.
It's not actually used anywhere, but it's not broken now!
This also moves the low-level and OS-specific GetLocalAddresses code to
C4NetIO where it's fitting better than in C4Network2Client.
We use ff02::1 as discovery multicast address.
This "all nodes" multicast address is good enough for discovery in the
local network as packets there are likely broadcasted over ethernet
anyways.
When many PXS were at the same location (e.g. because of fast/multiple pumps pumping into a basin), only one PXS per frame could be inserted because insertion of one PXS would postpone insertion of additional PXS in the same frame until they finished their slide movement.
This caused some scenarios like Rapid Refining to become very frustrating, because adding extra pumps didn't actually do anything (unless you tricked the insertion by putting the output into the basin).
Now insert them directly if slide movement led to an insertion position.
This should not break anything because script players are created by scripts and one may expect sane behaviour. This is useful to block entry for normal players into a team.
The extra object is called "Magma" to distinguish it from Lava and has a slightly different color on the symbol. In the pump menu, only "Lava" is shown and magma is turned on/off with it automatically.
It would be nice to have only one object and control a flag somehow. However, this is bound to cause us headaches later on (combining materials, etc.). This solution is probably least error-prone.
This is the goal in defense scenarios and controls the waves. In the future a league interface can also be build. The goal is to adapt the existing defense scenarios to this format (mostly internal changes and infinite waves). Also this should allow for easier creation of defense scenarios.
Using objects was blocked by the GUI menus and the ObjectControl() function anyway, but (!) it was not blocked for the old style menus that can still be used.
C4Update needs to access some internal data of C4Group and uses a
special derived class (C4GroupEx). Make everything it doesn't want to
tamper with private so it's more obvious what is and isn't accessed from
outside the class.
The pByChild parameter to C4Group::AdvanceFilePtr was never used except
to pass it to itself recursively, and C4Group::ProcessOut was never used
at all.
Systems that don't come with getopt/getopt_long in their runtime library
need to link to our private copy; link that and use the right const-ness
for its prototype.
Instead of jumping forward and back repeatedly per iteration, we're
moving the incrementor past the body, which is when it's supposed to be
executed anyway.
The king size weapons overloaded entire functions from their original objects. This was replaced by adding interfaces that allow for the manipulation of the desired values.
This was part of a bugfix in the ladder for Hazard: The ladder lets the Clonk execute a jump with Clonk.JumpSpeed / 2 at the top. This is useful for extra jumps and other things where you want to force the clonk to jump.
Regarding the ladder: The most of the problems with ladders arise from the OC implementation. Further commits may follow.
Of course, kept the old two modes: bullet and rocket (boompack) firing.
Bomb dropping for dropping fused iron bombs and dynamite sticks.
Liquid spray for spraying the landscape with whatever you like (of course, with water you get a firefighting plane!).
Balloon parachuting for midair action drops!
Object dropping - drop whatever you want!
* Correctly save in scenario: Dynamite count and fuses
* Allow recollection and placement of dynamite sticks
* Allow recollection of dynamite sticks into the box, in which case fuses are automatically cut
* Implement with less duplicate state (removed count, wire, wires and dynamite_sticks variables)
This also allows placement of more than five dynamite sticks from a single box by collecting more sticks after some of them are already on the wire. I don't see why not; it's fun and cannot really be abused.
The problem was that the call to Actmap.*.StartCallLadderOverloaded happend parallely with the ladder search effect and finished after the search effect call was finished, starting a wall jump animation after the Clonk grabbed the ladder.
The problem was that the call to Actmap.*.StartCallLadderOverloaded happend parallely with the ladder search effect and finished after the search effect call was finished, starting a wall jump animation after the Clonk grabbed the ladder.
Letting the constant resolver throw exceptions prevented us from doing
checking on later initializers anyway, so instead we'll send them to the
error handler. As a special bonus this makes it so we don't crash when
a global variable initializer has errors. Fixes#1850, #1855.
The material map is 1D texture that contains information about every
material-texture combination. There is no point in linear filtering,
i.e. trying to interpolate between two materials such as gold and granite
or whichever two materials happen to be adjacent in the material map texture.
This might or might not be relevant to #1841, but should be more correct
behavior in any case.
I don't know why the viewports are deleted with deleteLater(), but it leads
to an OpenGL context getting deselected behind our back, and so we don't know
when is a good time to re-select it. This leads to termination of the engine
when selecting File->Close (Ctrl+W) in the editor, because the graphics
re-initialization fails with no GL context active.
Instead, just delete the viewport widget immediately, which works fine at
least on Linux. This is also recommended by the Qt documentation at
http://doc.qt.io/qt-5/qopenglwidget.html.
When removing a viewport, then also remove it from the internal list of
viewports. Otherwise, we might attempt to delete it again later. Fixes
crash on editor shutdown on Linux.
This fixes a crash on Linux when exiting the editor. It was caused by
C4Console::~C4Console being called by the C++ runtime after after main()
returned. The C4Console destructor then goes and deletes all the Qt
resources (QApplication and friends), and that caused a segfault, maybe
because some of the static Qt structures have already been deallocated.
Fix this by making the destruction of the Qt components deterministic. Add
a function "DeleteConsoleWindow" which deletes all the Qt components, and
call this function in C4Console::Clear.
Extracted the basic functionality for HUDs from GUI_Controller to a library. This way, if you want to create a new HUD, you only have to include the library and all the desired components. Previously you had to copy the script from GUI_Controller, too. This holds of course only if you want to actually remove components from the HUD, and not just add to it.
Currently the GUI_Controller is referenced as the ID for the HUD, will change this to a callback.
By continuing to generate bytecode even after an error is found, we're
able to find more syntax errors and will also be able to keep the value
stack at the expected height.
When an error occurred during codegen of a function, the current
function pointer would not be reset to 0, leading to spurious warnings
about redeclaration of functions.
Uniform variables are read from the "Uniforms" proplist set on Scenario
or on individual objects. Proplist keys are uniform names. Values can
either be an int or an array of one to four ints in C4Script. In GLSL,
the uniforms then need a matching type (int/ivec2/ivec3/ivec4). There is
no error reporting; uniforms are only set if both name and type match.
The implementation walks the "Uniforms" proplists on each Draw call. We
may need to cache the uniform maps if this turns out to be too slow.
With the highest items being in the front, the tight grid layout has less reason to resort a major amount of the items every time items are added or removed. This results in a generally more stable layout.
This makes extra-slot containers not block an extra row anymore. However, they might jump around a bit. It might be a good idea to set their priority lower to make them always appear first.
When they would be in front, the tight grid layout would likely not move them around.
The TightGridLayout fills spaces more aggressively. This is slower but makes for a tighter layout. Finding the best layout is NP-complete. This here is just O(N^2) or so.
If a parse error occurs inside a declaration, the codegen should just go
on and deal with the next declaration instead of completely giving up on
the entire script.
9caaf1e introduced an external error handler for easier testing of
error conditions. The default error handler needs to count errors and
warnings if we want to display them, but didn't.
* Shows correct size in preview (by setting the scaling on the definition instead of in Construction)
* Can be oversized
* Avoid angles where all signs are facing parallel to the camera
* Unfortunately, rotation doesn't work well with Mesh Transform (uses the wrong rotation center for the graphics)
36/1000 is always 0 and doesn't make a lot of sense anyway. Use 1000/36
(aka 1000ms/36fps) instead so the UI thread has some time to rest.
Also use a Qt::PreciseTimer so Qt doesn't try to coalesce the scheduler
timer with other timers to save energy.
The old parser threw a standard compile error in this case; the
AST-based parser threw an ICE, which is ultimately the same thing but
made it sound like the parser was at fault. And maybe it is, and we
should allow code like "local a; func a() {}" but that seems like it
should be a conscious design decision.
C4Value already handles refcounting properly for us, so we don't need to
do it manually. It might still be worth manually refcounting them
to avoid the boxing/unboxing overhead, but it's only needed at load and
unload so it's not a priority at the moment.
By using an extern error handler in the script engine, we can mock that
handler and make sure something that should fail actually does, instead
of having to parse log messages.
Redefining new breaks perfectly valid code, but only on MSVC and only in
one particular configuration (Debug). This is very annoying because it
means people not using MSVC, or even people doing Release builds, can
write standards-conforming code which then may fail to build for other
people.
RunExpr will evaluate and return the value of a single expression.
RunCode will evaluate a full function body.
RunScript will compile a complete standalone script and return the
return value of its Main() function.
Depending on the mood of the linker, the editor may have been
constructed before and destroyed after the system-wide string table
because they weren't defined in the same file. Destruction of the editor
tries to load some strings, which would then access the already
destroyed string table and thus crash.
They never worked properly in network mode because all users would see the changes.
EditorProps, EditorActions and shape delegates now provide the functionality to have custom object editing widgets.
This also fixes a bug with the selection callback causing the object list to act up.
Parsing a function expression inside another function failed to reset
the code generator target to the containing function, so all following
bytecode would still be appended to the nested function, leaving the
container broken.
It doesn't make a lot of sense to keep console pointers around while the
objects and scripts have already been deleted. Clear them earlier so we
don't have any dangling pointers.
Set the default to a lot of clonks. This is useful so the "respawn at flagpole" rule works as expected even if users don't know about the base material setting.
* Engine would always open up in Fullscreen and then switch to Windowed
instead of just starting up as Windowed.
* Could not change resolution because bit depth or refresh rate did not match
* handle RefreshRate==0 as "any", just like windows
* Remember refresh rate in combo box that enumerates all the modes and
propagate to video mode setting instead of assuming all modes have the
same refresh rate.
* Report bit depth as 32 even if SDL tells us it's 24. Other parts of the
code require it to be equal to 32, but 24 works just fine.
* Changing from fullscreen to windowed when "Screen" was selected in
resolution combo box (i.e. iXRes==-1) makes the window tiny (0x0 pixels).
The last error is displayed in the GUI, so until now there was just a "(null)"
string there.
The whole (SDL) resolution switching code is completely broken as well, but
that's a different story...
If a local variable in a definition was set to a proplist inside the
Definition() callback, and that proplist contained cyclic references
then those references were leaked. Typically cyclic references for
script-created proplists are broken in
C4PropListScript::ClearScriptPropLists, however definition proplists
are changed to be static proplists in
C4PropList::FreezeAndMakeStaticRecursively.
To fix this, each script host maintains a list of proplists made static
by FreezeAndMakeStaticRecursively, and explicitly deletes all of these
proplists on Clear().
This leak also leads to an assertion failure inside
C4PropListScript::ClearScriptPropLists in debug mode, and can also be
observed by C4PropList::PropLists not being empty after game clear.
The definition in Objects.ocd/Helpers.ocd/UserAction.ocd constructs
cyclic proplists in its Definition() call. A simpler, more minimal way
to provoke the leak is the following (it provokes the leak but not the
assertion failure):
local bla;
func Definition(def)
{
bla = {};
bla.test = { Name="Test222" , Options = { Name="Test333" } };
bla.test.Options.Link = { Name="Test444", Blub=bla.test };
}
Use RegexSearch() instead, which is 100 times faster for large strings
(see benchmark results below).
Example benchmark:
global func TestFindSubstring(int iterations)
{
var result;
for (var i = 0; i < iterations; i++)
{
result = FindSubstring(hamlet, "and");
}
return result;
}
global func TestRegexSearch(int iterations)
{
var result;
for (var i = 0; i < iterations; i++)
{
result = RegexSearch(hamlet, "and");
}
return result;
}
global func RunBenchmark(int iterations)
{
StartScriptProfiler();
Log("FindSubstring: %d iterations", iterations);
var substr = TestFindSubstring(iterations);
Log("RegexSearch: %d iterations", iterations);
var regex = TestRegexSearch(iterations);
StopScriptProfiler();
if (!DeepEqual(regex, substr))
Log("Results differ: %v vs %v", substr, regex);
}
Results:
FindSubstring: 100 iterations
RegexSearch: 100 iterations
Profiler statistics:
==============================
48903ms Global.FindSubstring
48903ms Global.TestFindSubstring
47979ms Global.TakeString
00504ms Global.TestRegexSearch
00016ms Global.PushBack
==============================
As carrier-grade NATs are becoming common, many players cannot host
Clonk games at all. The simple STUN-like netpuncher from Clonk Rage
which was removed three years ago is already effective against some
DS-Lite NATs.
With some extensions, we should be able to make it work with more
restrictive NATs as well.
This reverts commit 72002cc366.
Bash variables are global by default. Therefore, recursing into sub-
dependencies was breaking ID updates in the dependency parent.
Mark variables that are local to each recursion step as local so that
their original value gets restored when the recursion returns.
Inclusion of the library buffed the damage wild chippies do by 100%. This is unintended. Chippies grow (and get stronger) through sucking blood.
A commit that changes this behavior should address this directly. (This commit also makes chippies gain size a bit faster - as a compromise.)
The additional check in StartGrowth reduces overhead in the animals (and possibly plants) library. It is kept in this commit to give reviewers an example case for the check.
Also adjust editor props for the change:
1. enum needs to create a copy, not a reference for the default value of an option if it is defined inline
2. Always use proper GetName() resolution on property group names even if a static name would be available
The torch timer was #1 script in a profiler run of a scenario with 10 torches.
Reduce to 1/4th of the calls. Actually, I think it looks better now (less regular, more torch-y).
commit 1abfae50c6454c8f5bab10bff753fb472f0596d0
Author: Armin Schäfer <arminnessie@gmail.com>
Date: Wed Aug 3 00:56:40 2016 +0200
Make shark slower (only twice as fast as the Clonk) and reactivate FastSwim animation.
commit b35db07894be864978a6b03609eb3d754b622705
Author: Armin Schäfer <arminnessie@gmail.com>
Date: Thu Jul 21 22:24:48 2016 +0200
Shark: Fix shark not swimming for a while when Clonk was too near.
commit f1495371394796e4a2d984049c026eaa66a0d30e
Author: Armin Schäfer <arminnessie@gmail.com>
Date: Sun Jul 3 19:48:22 2016 +0200
Shark: Revert wrong location of the shark.
commit 437f911629c8ec9ee1c587e653790378b0d8fd17
Author: Armin Schäfer <arminnessie@gmail.com>
Date: Sun Jul 3 19:44:49 2016 +0200
Shark: Fix one turning bug, it can not be big enough to cause a mesh bug when turning around; shark is a bit slower when attacking (hopefully it can not jump out of the water now)
commit 28d0a9dfbad4e2b4c42295e73d8d42e5495b0e37
Author: Armin Schäfer <arminnessie@gmail.com>
Date: Sat Mar 26 01:28:19 2016 +0100
Move shark to Objects.ocd and add sharks to Clonkomotive on hard settings.
commit 000d162fb5c36225fdd215d1d30336a1c926ec27
Author: Armin Schäfer <arminnessie@gmail.com>
Date: Sat Mar 26 01:09:55 2016 +0100
Shark: Fix bugs.
commit be201ffd6424203bf2b9b3a2a8496b3d41ec3122
Author: Armin Schäfer <arminnessie@gmail.com>
Date: Sat Feb 20 14:48:12 2016 +0100
Shark update. Fix animation when attacking.
commit 7dc24e93fa19f26cc2f3344ac8267b81b4fd3eee
Author: Armin Schäfer <arminnessie@gmail.com>
Date: Sat Jan 23 22:36:24 2016 +0100
Delete the patch.txt from my last commit.
commit 36e828fb7545fb6c2538c728844f0b4dc97bfcc5
Author: Armin Schäfer <arminnessie@gmail.com>
Date: Sat Jan 23 17:38:29 2016 +0100
Add experimental Shark scenario.
It created SetName("") entries because def->GetName() has a fallback to the internal name while obj->GetName() does not.
Just use .Name instead. Objects with custom naming (overloaded GetName()) need to overload name saving anyway.
The musket was not a very popular and useful weapon, being inferior to the bow. It now shoots 5 weaker bullets in one shot with less damage per bullet, this might require some further testing and fine-tuning. Also the weaker bullets mean that they can be used in a gatling-gun (WIP) and in the airplane as well.
This fix might be dangerous, I do not know it. I have no real idea what this line was supposed to do. But it certainly prevented the release use command from getting to the used item in certain corner cases (right between loading and aiming).
I tested a bunch of vehicle and they work fine so far. So maybe this line was useless and harmful after all.
If a timer=1-effect registered another timer=1-effect into the same object, it could cause an endless loop. This happened if the timer in the sequence object was set to 1.
Rudimentary handling of air pumping added to the pump and of course the helmet. The functions of the helmet concerning air pumping can maybe later used for a library.
*: not all damage is reduced, does not help against explosions, fire, asphyxiation or corrosion. We assume no liability for any deaths or injuries occurred while wearing.
The problem occurred as soon as the clonk's leg vertices passed the edge. It seems the engine does not really align the bottom vertex to the material. However, the bottom vertex does have CNAT_Bottom & _Left & _Right, in theory it should be properly attached. Maybe this is a little bit broken engine-wise or maybe assigning both left and right to a vertex isn't supported?
Because the lower vertex (foot vertex) isn't attached, the clonk falls down onto its leg vertex and gets stuck in an endless loop of Scale, Jump, Walk, Scale, ...
When pressing left/right, this is no problem as the clonk will be pushed towards the edge when walking and soon touch it with its foot vertex (I assume at this point regular engine behaviour kicks in).
I added a little helper in the scale effect that sets COMD_UpLeft / UpRight whenever this situation is detected and only Up is pressed. 2 frames (1 is not enough) after the effect ended, the ComDir will reset to COMD_Up. It is then possible to climb an edge and stand still on top of it.
Maybe not a perfect solution (a perfect solution would probably be to fix attachment in the engine but I couldn't pinpoint the exact problem) but it works for now.
The script players was not treated correctly by the goals, so joining it automatically would break stuff. While I still like the implications of an automatic script player, it was too much of a hassle for now.
Find_AnimalHostile works around the main issue as it allows just using Find_AnimalHostile and automatically have the animal work for both neutral owners and as pets. It does not allow for the distinction of hostile neutral and friendly neutral, though.
In every team, the same number of players will now load their grenade
launcher before the round starts. If there's a team with more players,
some players won't be able to shoot immediately.
The custom title bar caused a lot of problems. Particularly turning it on and off between docked and undocked modes caused some internal trouble with the rendering going off. It also didn't have a close button.
Fortunately, the desired font and highlight effect of selected viewports can also be achieved with style sheets on the dock.
The callbacks from PlayerControl aren't used anywhere right now and there's only two unrelated internal functions in the GUI list menu with the same name. So the parameter checker emits a warning here.
Solve it by renaming the internal functions.
This makes the selection of the Q slot slightly more awkward because you select the target slot in between. Or to say otherwise: it is kind of like it was before.
Will construct the construction without the needed material. I often needed to test stuff with construction sites and always had to script-create all the material which is tedious.
All GetCarry* callbacks receive a parameter whether they are held in this slot and can then return a different display mode!
I also took the opportunity to restructure many scripts in a similar way.
Values are used for all starting clonks and all clonks created later in the game for this player (e.g. respawns) after spawning from the spawn point with these settings.
I deserialised the skeleton file and removed some bone positions that I guess were wrongfully included because they concerned the left (non-carrying) arm. I think I didn't break anything but if so, this patch is to be reverted.
The GTK code does not work with the Qt editor. The simpler SDL2 platform
does, so we have little reason to keep the GTK code.
Note that GTK is still a dependency for mape.
Discussion: http://forum.openclonk.org/topic_show.pl?tid=3328
As suggested by Zapper in this posting: http://forum.openclonk.org/topic_show.pl?pid=31073#pid31073.
This way is probably the only way item usage will ever work on Q. For now, this reverses the previous changes. Q will again react on key down.
This makes a very fundamental change with quick switch: The switching action is now performed on the key release instead of the key press. Let's see if this performs badly for players.
This will prepare the quick switch system according to Maikel's suggestion (http://forum.openclonk.org/topic_show.pl?pid=31070). The highlighting method is open to discussion. Currently, font colour and style are similar to the interaction key above the action bar icon. But it is very well possible that this will look bad when the key name is very long.
This will give you visible feedback if the hook is fired or not. Perfect for dual hook handling situations. Library_HasExtraSlot is used to show this but IsContainer returns false. This will prevent hook extraction using the interaction menu. Removing the hook from the grapple bow will cause errors (this should probably be taken care of sometime).
Redefining new breaks perfectly valid code, but only on MSVC and only in
one particular configuration (Debug). This is very annoying because it
means people not using MSVC, or even people doing Release builds, can
write standards-conforming code which then may fail to build for other
people.
* Player enters circular region
* Game starts (after player joins)
* Player joins
* Player removed
* All goals fulfilled
* Clonk death
* Construction of structure
* Production of item
This makes it more accessible in the editor. Otherwise, there would be "libraries/constructor" folders in the object creator with the construction site as the only contained definition.
Certain ladders (in an expansion pack) should not be climbable, but this depends on the clonk that wants to climb on the ladder. Added the clonk as a second parameter to the callback, in order to not mess up the callback structure of other external packs.
Storing the pointer in QModelIndex could sometimes keep invalid memory on the persistent model indices. Because re-organizing these memory locations would be a nightmare and we only go two levels deep anyway, just store the parent index in the internal pointer and look up the actual property on the fly.
This is an emergency fallback for older Intel drivers on Windows, which
do not support OpenGL 3.2. As we're creating 3.2 contexts mostly to
access the Core profile, which was not available in earlier versions,
falling back to 3.1 should be fine; I don't think we're using anything
specific to 3.2.
It serializes objects using a selective SaveScenarioObjects script callback and then just executes the generated script. This automatically saves important properties, connects switches and doors, etc.
This change also solves the problem that duplicating an elevator plus case would create two elevator cases.
If execution fails (e.g. because of script errors or because a non-saveable object was duplicated), the method falls back to the legacy duplication method of creating objects with the same prototypes at the same position.
C4Group::SearchNextEntry would waste lots of cycles looking up file
attributes that were never inspected afterwards. Since all we want is
the file size, and we already get that for free from FindFirstFile and
FindNextFile, store it with the directory iterator instead of querying
it at every iteration.
This reduces load times on my machine by almost half, tested across
several different scenarios.
Our hardware-based skinning doesn't work on certain Intel graphics
devices. Fall back to software skinning on GPUs that return an OpenGL
3.1 context even though we explicitly request a 3.2 one.
Might fix#1459, #1689.
The hammer will now only construct definitions that have the callback "IsHammerBuidable". This will exclude all C4D_Structure objects that are not buildings and can't be build in a meaningful way.
Also, with the carry heavy branch I want to test adhoc built lorries (lorries as construction sites). Sven suggested this.
So it turns out that the fix stops the engine from crashing, but it
still doesn't seem to generate valid code - Aul emits an internal error
at runtime.
The problems here were:
- the pickaxe component list returned [[Metal, 1], [Wood, 1]] instead of [[Wood, 1], [Metal, 1]]. This may be a result of the new component system with proplists; probably the components are sorted alphabetically now
The problems here were:
- the foundry cannot take 400 water from ice if it has a fill limit
- the pump cannot pump anything into the object if it has no fill limit
This is debatable. Let's see how this feels ingame and revert it in case we don't like it.
I like it because I think it gives valuable feedback to the players (and thus can reduce frustration coming from unnecessary actions). But it might also feel like a bug to players.
You could put e.g. tools into the barrel using the interaction menu. This would lead to a script error later, when the barrel did Contents()->GetLiquidType().
PS: And the RejectStack function is part of a private internal interface. I made that clear so the next one does not have to look it up again.
- The new code works with my router while libupnp didn't. :)
- There are some unexplainable crashes in libupnp: #1640
- Using miniupnpc seems to be less complex than libupnp.
- Apparently, miniupnpc also works on Windows, so we may be able to use
it for all platforms.
Disadvantage: UPnP queries aren't asynchronous anymore, but they seem to
be pretty fast (< 1 s).
It could happen that the objects were cleared (after evaluation screen / on section change) but a particle list would remain that would still point to an object (and would then access it).
I am not exactly sure how that could happen, because objects should clear their particle lists on removal (and thus shouldn't really need a ClearPointers).
There is a tiny chance that this points to another bug somewhere in the object removal - that's just a random guess though.
Anyway, this should fix the infamous Knüppeln crash.
Declaring a local variable inside any function works the same way as
declaring it in top-level scope, which gets a bit weird if done inside a
function inside a constant proplist, but is at least consistent.
Thanks to Flinti for reporting this.
On High-DPI displays, the mouse cursor is very tiny. We'll probably want
some high-resolution cursor graphics at some point, but the current ones
scale good enough.
This allows to remove the engine functionality and is based on the property Components = [[def1, amount1], [def2, amount2], ...]. Follow up commits will remove the engine functionality.
All the other effect callbacks silently ignored missing functions, either
by using the Call variant that doesn't complain about it, or checking for
the missing function themselves.
This makes the special effect properties useable without the "this." prefix,
makes the various useful global functions available as well as
effect-specific functions.
Effects with prototypes were supposed to inherit their names from the
prototype, but the effect prototypes are also supposed to get their names
from ParentKeyName, which is not inherited. Maybe that'll change, but for
now this matches how old effects work.
Apparently this is recommended so that a std::vector actually uses the
move constructor. In any case, the second parameter wasn't used, so this is
a nice simplification as well.
Employ variadic template arguments and more rvalue references for this.
Sadly, StdParameterAdapt itself is even more complicated, since it has to
store the parameters instead of just forwarding them, so the limit is still
two parameters. But that's twice as much as before in many cases.
This commit contains a fairly substantial rewrite of the C4Script code
generator. Instead of generating bytecode while parsing the script,
we're now parsing the script into a syntax tree, and have any further
processing happen on that instead of the raw source.
At this time, the code generator emits the same bytecode as the old
parser; there are several optimization opportunities that arise from the
new possibility to emit code out of order from its specification by the
author.
Compared to the old compiler, this one is still rather deficient when
dealing with incorrect code; it's also not emitting several warnings
that used to be diagnosed.
Thanks to ck, who noticed. Apparently it got lost when reverting some changes back and forth for testing, because I had one revision where I didn't need it anymore but I reverted most of that.
Some particles were visibly missing. The reason was apparently that the VAO was initialized with an IBO that was yet too small (because not all particles were created yet).
To be honest, I don't know why the IBO needs to be rebound as the identifier itself does not change(?) but maybe OpenGL optimizes some stuff and needs the size fixed?
Steps to reproduce: In OneMillionParticles.ocs, make Test3 be the first test (otherwise the IBO would have been large enough). You would now not see all of the fireworks.
The issue was introduced in e13cda4bd0
Otherwise the IBO is created from scratch for every particle that is e.g. created in a for loop. This is extremely slow and unnecessary.
The symptoms was that OneMillionParticles appeared to 'freeze' on the non-batch creation test. (Hint: it didn't freeze, it just took forever).
The C++ standard says that it doesn't matter whether you forward declare
something as struct or class and then define it using the other keyword.
Unfortunately MSVC adds those keywords to its name mangling scheme,
which breaks things.
Unfortunately, there doesn't seem to be an easy way to apply
multisampling changes in SDL. As a workaround, a message requesting the
player to restart the game is shown.
Added liquid objects for acid, lava, water and the new material oil. Expanded power system unit test and added some more unit tests for the producer system and liquid containers.
This unifies the lookup for local variables and functions. Its slightly
awkward that global functions can overload if and Par now, but local
variables already could.
Since GRBroadcast calls all goal and rule objects and the scenario,
there is a high likelyhood that not all of them implement whatever
arbitrary callback is called. Instead of throwing script errors about
calling undefined functions, just swallow that error and continue.
This should eventually replace the Prototype property, so that proplists
can be used as a key-value-storage without any hidden gotchas.
The Prototype is such a magical property that any code dealing with all
properties has to special-case it anyway, and isn't even returned by
GetProperties().
Both the initial “selected” and “last” inventory slots were initialized
to 0, making Q useless. Many melees give more than one item to the
player, filling up from the first slot. Having Q switch to the second
slot initially is better than doing nothing, which will never happen
later on.
Decrease their mass to prevent too much damage when having a direct hit plus explosion. Also decrease the impact of the iron bomb explosion a bit to make it less overpowered.
This even enables some simplification in the CompileFuncs, since the global
effects were already put in the same section as the other ScriptEngine
parts. The callback for updates due to relinks also fits nicely.
The reset in C4Game::Default was redundant with C4Game::Clear already.
This accessor does not need to be virtual itself, because we don't want
people to override it; it calls the nonconst accessor anyway, which is
virtual.
Several issues:
- The RNG wasn't copied with the value provider (which is always
copied), resulting in unseeded RNGs.
- Separate PCG streams with the same seed start with identical values.
As particles often draw only a single value, we just always advance
the RNG a bit to make the streams diverge.
- The C++ specification requires a <= b for its distributions, but that
wasn't guaranteed by the particle startValue/endValue.
.. so that small resolutions do not lead to even smaller scrollbars next to the power information. It's still not very aesthethic when it's multiline (because it's just so much text) but now it doesn't look horribly broken at least.
The window would always use its very own rectangle for clipping - bad luck if it was larger than the parent.
Now children can only additionally restrict the parent rectangle (which defaults to the whole screen at root).
Discovered with valgrind. Previously, some memory that later gets freed using
free(...) (in StdBuf::Clear) was allocated with new char[...] rather than
malloc, in which case delete[] should be used to free them.
This will make lighting look weird again for meshes flipped via FlipDir.
Avoid doing that until we implement FlipDir for meshes via an internal
MeshTransform.
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().
a) make sure the context is deselected on destruction, so that
CStdGL::Clear() destructor doesn't try to deselect a non-existing context.
b) Calling Clear() in CStdGLCtx::~CStdGLCtx() does only call
CStdGLCtx::Clear(), even though Clear() is virtual. The reason is that by
the time the CStdGLCtx destructor is executed, the CStdGLCtxQt part of the
object has already been destructed. Therefore, make CStdGLCtx::Clear() safe
to be run without the context ever having been initialized, and explicitly
call CStdGLCtxQt::Clear() in CStdGLCtxQt::~CStdGLCtxQt(). This is certainly
not the most elegant way to handle this, but it should do the job for now.
This revealed a bug: Transferring single arrows to the surrounding with the "transfer all button" leaves single arrows in the environment, instead of actual stacks.
Transferring them with single clicks stacks the arrows though.
The trick was that the Clonk does not exit the object right away, but gets a drop command instead. Furthermore, it was confusing that the Collection2-callback never actually happens in this situation.
The original implementation is ok, but why check the value if it would not change anyway? In the new implementation the variable lives only where it can actually change, and so does the if-clause.
Transfer of items from one container to another is handled differently between the following actions: a) select items for transfer in the inventory box; b) transfer all items with the transfer-all-arrows.
This should be made consistent, especially since action a) seems to have an unnecessary special case (marked with TODO).
As a first step the methods were simply extracted.
Instead of making the user count lines from the shader log, we'll now
emit #line directives and a file number->name mapping to make it easier
to figure out which file and line the error message comes from.
Since LTCG is enabled now, we don't have to define every function inside
the headers for ~xXx super speed xXx~, which means we can strip the
headers down to their bare minimum and reduce interdependencies and
therefore recompilation times by a lot.
Instead of discarding all previous debug CXXFLAGS and replacing them
with generic ones, actually interpolate CMAKE_CXX_FLAGS_DEBUG into a
value to assign to CMAKE_CXX_FLAGS_DEBUG.
Having a build type that's called "Release" makes people thing they
should use it when they want optimized builds. They shouldn't. They
should be using RelWithDebInfo instead, so at least trying to debug
errors isn't entirely futile.
Mesh rotation needs to happen as part of the MeshTransform so lighting
is applied correctly. DrawTransform applies after lighting which made
rotated meshes look weird.
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.
The SDL port used to define a separate set of key codes differing from
the usual ones. The SDL codes are now translated to make the Qt input
easy.
This also fixes a broken keycode for the '0' key.
The QOpenGLWidget is set up to render into a custom framebuffer, and by
resetting to render into the default framebuffer, we don't draw anything in
the buffer that is actually going to be displayed by the widget.
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.
- Add assignments for switching interaction and pickup targets (just
like the keyboard control).
- Remove double assignments of the sticks for walking and aiming. The
left stick is now exclusively for walking and the right stick
exclusively for aiming.
The earth object did not include _inherited(...) in the Construction() callback. Thus it was not initialized as a stackable object correctly. Fortunately the other stackable objects did not have this problem.
Nonetheless I added a unit test, so that we can identify similar problems in the future.
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.
The plane limits in C4ObjectList::Draw were not properly checked,
leading to objects in front of the landscape being drawn twice (once
before the landscape was rendered, and once after).
The landscape renderer used to store texture data into the default 1D
texture, which works but is a bad idea for several reasons (and would
have broken if we had a reason to use another 1D texture anywhere else).
The available gamepads are distributed automatically among players.
This also implements controller hot-plugging: It is possible to start a
game without a controller and plug it in later, and to reconnect a
controller after plugging it out.
We want one gamepad key mapping to work with multiple gamepads, so
including the id there doesn't make sense.
Additionally, the gamepad id may change during the game (controller
hot-plugging).
The icons currently only show Xbox 360 controller labeling. The icon set
also includes icons for PlayStation controllers, so we could extend this
in the future.
This also removes the controller id from the control definitions,
instead defaulting to 0. This doesn't change anything for now as we only
had definitions for controller 0 anyways.
It is now possible to control all GUI menus using the left stick or the
dpad, along with the A and B buttons on the controller.
This also doubles the button emulation dead zone to make navigating the
menus with the stick easier.
To keep compatibility with scripts which expect only binary buttons,
this adds a third parameter to the function which enables the new
functionality.
Bonus /script to test the controller stick x axis:
Schedule(GetCursor(), "Message(\"%d / %d\", GetPlayerControlState(0, CON_Left, true), GetPlayerControlState(0, CON_Right, true))", 10, 100000000)
Note that the values will be inconsistent if multiple analog sticks are
bound to the same control, as values from one stick will overwrite those
from the other one. This can happen even if you move only one stick.
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 treats barrels the same as itself when it comes to extracting liquids. This removes the need for the callback OnFuelRemoved() in the barrel, as well as the stupid definition call from the barrel to the steam engine.
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.
The steam engine does not remove the barrels, it just empties them. Made power system unit test 19 end if both pumps are pumping, this seems to be the intention of the unit test. Added power system unit test 20: Steam engine fueled by oil barrels.
Made the steam engine interface more modular, removing duplicate code. Added a callback when refilling fuel that allows the objects not to be removed. This is important for barrels, because barrels will just empty their contents, they should not vanish!
The pump actually stores liquid until it can pump. This may not be desired, but it was like that before my changes already. This probably is better than having it drop excess material at the pump.
The pump can transfer liquids to and from liquid containers now. Changed the material storage from material index to material name now, because liquid containers may contain fantasy liquids, too. The pipe cannot output such imaginary liquids though, so only transfer between compatible containers is possible.
The pipe can be connected from the interaction menu now, too. Expanded the disconnection logic, because more problems arise when the pipe can still be connected to other structures - it would be sufficient to remove the line, but that could be annoying:
- if the pipe is connected to a container, then you can disconnect the pipe from that liquid tank and it will still be connected to the pump
- if you disconnect the pipe from the pump, then it will disconnect from the liquid tank as well
Maybe this is confusing to the user, we can still kick that out later again.
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
With the SDL_GameController interface, buttons and axes have actual
names we can refer to. This also allows for advanced mappings using both
sticks (this probably needs script changes) as well as the triggers.
Unmodified readline relies on, but doesn't link to, a termcap library.
Several Linux distributions patch this, but others don't; to avoid build
failures, we'll just link to a library that provides termcap symbols
even though we don't use them ourselves. Fixes Github #15.
It is possible to set the amount of resources to be extracted with an additional parameter in SetResource() now. The default amount to be extracted is 95 percent, which is the same behaviour as before the changes.
Deciphered what some of the functions are good for, since the original code is kind of cryptic. This should help again when expanding to diggable materials.
The steam engine treats barrels the same as itself when it comes to extracting liquids. This removes the need for the callback OnFuelRemoved() in the barrel, as well as the stupid definition call from the barrel to the steam engine.
Previously, global particles would be drawn even in front of Plane 1000+ (GUI) objects. Additionally, it was impossible to specify particles that were supposed to always be in front of all other particles (e.g. fog, clouds, emulated FoW, ...).
Now, you can attach particles to an object on plane 901+ and have them be in front of everything else.
The FoW renderer would try drawing to texture coordinates one pixel
too high (i.e. if the texture was 256 pixels high, it would draw to
pixels with 1 <= y <= 256 instead of 0..255).
C++11 forbids conforming compilers from performing the deprecated
conversion from a string literal to non-const char* or wchar_t*. Most
compilers however still do it by default because not doing it breaks
lots of legacy code. We don't have any of this legacy code anymore, so
we can disable the conversion.
The lpClass parameter isn't used, and it is valid to pass NULL for it.
It is, however, not valid to pass a string literal, because the
conversion to nonconst char* has been deprecated in C++ for a long time
and doesn't exist anymore in C++11.
Quoth MSDN: "The Unicode version of this function, CreateProcessW, can
modify the contents of this string. Therefore, this parameter cannot be
a pointer to read-only memory (such as a const variable or a literal
string). If this parameter is a constant string, the function may cause
an access violation."
It can, however, be NULL, which does the right thing automatically.
It seems like an odd decision to add a layer of indirection to this,
especially since it's just a pointer to int instead of a pointer to a
larger structure.
This messes up so many things as one could have expected. Instead we do the sensible thing and enable it only in the test scenario. For future reference all sequences involving an elevator and NPC clonks are broken with this feature.
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.
The red color channel calculation could overflow into the sign bit,
which is undefined behavior. At least one compiler takes advantage of
this and assumes it cannot happen, resulting in incorrect results.
BltAlphaAdd looks similar, but does in fact not have this bug because it
shifts the color channel far enough that multiplication can't overflow.
The script now just sets visibility per player (VIS_Select) instead of creating one dummy object per player. It also uses the object directly instead of indirecting everything through an effect (the effect couldn't be used on other objects anyway).
The steam engine does not remove the barrels, it just empties them. Made power system unit test 19 end if both pumps are pumping, this seems to be the intention of the unit test. Added power system unit test 20: Steam engine fueled by oil barrels.
Made the steam engine interface more modular, removing duplicate code. Added a callback when refilling fuel that allows the objects not to be removed. This is important for barrels, because barrels will just empty their contents, they should not vanish!
..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.
Otherwise, you could open a menu on mouse-down, which would then block the mouse-up event. The control system (not the script but the engine!) would then never know that the button was released and issue a key event with repeated=1 when you pressed the button the next time.
This could lead to issues.
If the gamepad code initialized the SDL video subsystem, GTK+ crashed in
libX11. Or something along those lines.
Making the optional subsystems using SDL for gamepads and audio use
SDL_InitSubSystem and only the SDL Application port do the full SDL_Init
is the proper way to do things in any case.
It used a mix of tabs and spaces for indentation, and tabs to separate the
columns, which doesn't work with variable tab sizes and variable column
widths. Use tabs for indentation and spaces for column separation.
The pump actually stores liquid until it can pump. This may not be desired, but it was like that before my changes already. This probably is better than having it drop excess material at the pump.
The pump can transfer liquids to and from liquid containers now. Changed the material storage from material index to material name now, because liquid containers may contain fantasy liquids, too. The pipe cannot output such imaginary liquids though, so only transfer between compatible containers is possible.
The pipe can be connected from the interaction menu now, too. Expanded the disconnection logic, because more problems arise when the pipe can still be connected to other structures - it would be sufficient to remove the line, but that could be annoying:
- if the pipe is connected to a container, then you can disconnect the pipe from that liquid tank and it will still be connected to the pump
- if you disconnect the pipe from the pump, then it will disconnect from the liquid tank as well
Maybe this is confusing to the user, we can still kick that out later again.
Which means that you can
1) Drag around the tree / nest in editor mode
2) Shoot zapnests that were put into a catapult by a scenario designer
3) Can RemoveObject a tree and the nest will fall down (instead of keep floating)
4) Can put zap nests in earth (just like in CR!)
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.
This revealed that the code for setting Par.i was wrong before, but didn't
matter because the jump target for all CONDN was set afterwards. But the
jumptarget for COND was set directly, and must be adjusted to account for
the bytecode that gets optimized away.
It pointed always to Pars + Func->GetParCount(). The only users were
VARN_CONTEXT, which can be replaced with PARN_CONTEXT that way, and
FOREACH_NEXT, where the parser can do the math and simply give a number
relative to the current stack position, like regular variable usages do.
This can happen when an engine function is made to call a script function
when the stack is almost exhausted. Since there was nothing catching that
exception, it'd mean a program abort. Move the bulk of the exception
handler to the outer Exec function, and only keep the saving of the exact
code position in the inner one.
While at it, simplify the pushing of the parameters to simply push the
right amount of parameters instead of pushing ten and then popping the
excess. Also move the creation of dummy parameters for DirectExec into
DirectExec().
In earlier C4Script versions, there were multiple variants of expressions,
all followed by the same operator options, but nowadays everything is more
uniform.
The GTK and OS X platforms already ignored the requested bit depth and
always used 32 bit. Windows and SDL would set a 16 bit color depth for
the screen, but still did all of the rendering short of the final
present in 32 bit.
In windowed mode, we shouldn't stop rendering just because we have lost
focus. However, we don't need to render at full framerate; throttling to
5 fps should be sufficient. Note though that we still have to calculate
game ticks at full speed so network games don't slow down when a player
tabs out of the game.
Even though we (might) change the resolution, that doesn't result in
loss of textures because we don't recreate the OpenGL context. Therefore
we also don't have to restore their data. I believe this code is a relic
from the DirectX renderer, which would lose textures when switching away
from a fullscreen window.
Previously, it was checked incorrectly whether the action was "Dig". Then the check was thrown out completely in https://git.openclonk.org/openclonk.git/commit/39e86474fccbd54eb357175d2b8fbec5c60639ab - which did remove the warning but not solve the defect.
This should be a proper fix. The shovel only does stuff when the user is digging AND actually using this very shovel for it.
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
When an UI element was only visible to a player (via the Player property), it still allowed ALL players to click on buttons.
I am wondering why noone else noticed that bug before. It's possible that it didn't show when the visibility was set via the menu's Target (instead of the Player property).
Maybe this was the cause of the "clicks sometimes do nothing" bug?
It isn't enough to check the top-level mesh, because attached meshes also
get a transformation from script. At least cotton branches sometimes do
that.
So check the matrix directly before using it and skip rendering.
"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.
Unlike GLX, the OpenGL function pointers are context-dependant. Because we
need an extension function to create the context we're going to use, we
first need to create a temporary context. Since this is independent of the
library used to fetch the function pointers, decouple it from glewInit().
It's not clear that the glXCreateNewContext fallback does anyone any good
because it can't create the Core Profile Context we need, but better a
fallback message followed by Shader compilation errors than an obscure
X11 protocoll error. Probably.
Extracted the dig speed modification part to a separate function, so that other scenarios can easily overload this. Setting the value to 75% of the input speed provided a good handling in my tests. This is not included in this commit, feel free to experiment with it first.
Structures can use the definition call ConstructionPreview(Previewer Object, Overlay, Direction) to add any overlay to the previewer. It will be coloured accordingly.
Clouds can change their basic color with SetCloudRGB(r, g, b) now, for more ambient effects. This does not mess with the cloud shading, because the color is scaled appropriately.
This bug manifested itself in mysteriously growing PropLists with nil keys.
Some usages of Clear were simply to clean the newly-allocated table, and
need to continue to do so.
It isn't clear whether that call is necessary since the C4AulScriptEngine
constructor already does this, but it is clear that duplicating the call
all over is a bad idea.
This allows the removal of quite a few return C4Void();.
Also stop pretending that Nillable<void> is the same class as Nillable<T>.
Its only function was as an implementation detail for C4Void, which doesn't
need any implementation details anymore.
This avoids duplication of code in C4AulObjectFunc and C4AulEngineFunc
at the cost of boilerplate code working around the lack of partial
function template spezializations.
Instead of ThisImpl and ExecImpl, we could have multiple C4AulEngineFunc
spezializations deriving from a common template, but that would require
even longer and duplicated boilerplate.
This allows one to use the C4Value constructor instead of
C4ValueConv. To avoid unintended implicit conversions like
const char * to bool, add a private template constructor that
catches everything not in the list of intended constructors.
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"
In the long term, there is no reason DirectExec should be concerned with
C4AulScript/C4ScriptHost. In the meantime, the lookup code from Fneval can
be moved into the function.
This allows eval in scenario script to access scenario script locals, but
that seems harmless.
Instead of tracking the status with a variable, simply test the loop-end
condition directly, and reduce code duplication between empty and non-empty
array contents.
Most of the changes are for exception safety. The parser references the
function stored in Fn when the function body contains a syntax error, so
the function has to stay around. In order to avoid memory leaks, store the
function and its containing proplist in their destinations before they get
fully parsed.
This doesn't allow functions directly in static constants or arrays.
Future work: Putting the owning proplist in the scope chain.
The C4AulScript containing the source of the function was already mostly
used to get the relevant proplist or available from context. This will
allow more than one proplist plus the global one per scripthost to contain
functions.
Apparently, this wasn't done already because of compatibility concerns. The
beginning of a release cycle is the perfect moment to finally complete the
prevention of using deleted objects from script.
USE_WIN32_WINDOWS was previously defined in PlatformAbstraction.h. Move it
to CMakeLists.txt and config.h like its peers. Replace USE_X11 with USE_GTK
or GDK_WINDOWING_X11 as appropriate.
Min/Max with array parameter will return the smallest/largest value of
all elements of the array. If any array element is not an integer, nor
convertible to integer, the function will fail.
I'm not a huge fan of testing for warnings by hijacking the logging
routines, but right now there's no way to exfiltrate warnings from Aul
any other way, so it'll have to do.
Overriding the logging functions from C4SimpleLog.cpp has the nice
additional advantage that expected runtime errors no longer get written
to stdout - this is okay because we're already checking that an
exception is thrown.
I guess the UI elements expect their position to already be corrected by cgo.X/Y. Or they never cared because they were in front of the upper board.
I am not sure, maybe the correct solution would be to actually position all elements lower (instead of adjusting for it when passing mouse input or drawing)? Currently the position is relative to the upper board's edge.
Anyway, this works for now.
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!
Otherwise, if a window was GUI_FitChildren and the text would NOT trigger a scrollbar, the window height was set to 0 (because the text height was only taken into account when rawTextHeight - 1 > rcBounds.Hgt).
A little rant about why I 'hardcoded' the value 2.9em:
If you are using constants to specify some positions, please give the meaningful names so that other people can work with them. E.g. calling something "menu_height" and then using it to adjust the X position AND the Y position of a BUTTON probably means it's not the "menu_height"...
I believe that the current "dynamic layout" will terribly break if someone would e.g. decide that the menu should be one line higher (because hey, then everything else would also move).
The real solution is to rewrite the layout of the menu to be dynamic and use constants (because currently it isn't and doesn't, it just tries to.).
Previously, text windows would just change their own size and leave cropping and scrolling to their parent. This made the code easier, but was apparently unintuitive for scripters.
Now text windows do not change their size but show a scrollbar themselves (unless GUI_FitChildren or GUI_NoCrop of course).
This implied some other changes, because now parents without a scroll bar need to clip, too. (Or the clipping needs to be moved to the child window. But then it would have to be made sure that menu decoration can still go out of the bounds.)
And this also needed some script fixes where scripters assumed the text windows would not scroll (and thus made them smaller than 1em).
related to https://git.openclonk.org/openclonk.git/commit/46ad28ea652fad34814a866f3b9c305aa7cc6faa
Not sure why this broke, maybe glGetIntegerv does not return the current
polygon mode anymore. Either way, we don't need to remember the previous
setting but can just always reset it to GL_FILL afterwards.
The buffer offset was encoded in the VAO which would be shared across all
submeshes. Instead, don't encode the buffer offset into the VAO but apply it
with glDrawElementsBaseVertex().
glDrawElements needs an IBO when using a core profile. The particle
system's IBO is actually quite static since it's always a triangle
strip with 2 triangles followed by a PRI. Therefore, this reduces the
amount of data we have to send to the GPU compared to the previous
solution.
Also, remove the workaround when glPrimitiveRestartIndex is not
available since it is always available with OpenGL 3.1 and when using
a core profile we are guaranteed to have OpenGL 3.1 anyway.
This is required for glDrawElements() with a core profile. Furthermore, for
meshes that have a fixed face ordering (non-transparent meshes at 100%
completion), this puts more static data on the GPU that we don't have to
upload every frame.
For meshes with non-fixed face ordering, we still have to upload faces every
frame, since the ordering might change if the mesh rotates. We could still
improve this by figuring out if the order actually changed after the sort
step, and only update to the GPU if it has. In many cases it hasn't, so there
is some potential for more optimization there. But that's for later.
This code was basically never used anyway, since the
ARB_non_power_of_two extension is always available since OpenGL 2.0.
The GLEW check for the extension fails however as soon as we select
a OpenGL 3 core profile, and the texture sizes will be unnecessarily
adjusted again.
Basically add another layer of indirection around accessing VAOs. The problem
is that VAOs are not shared between OpenGL contexts. This mechanism allows to
treat them mostly as if they were shared if they are only accessed through
the API defined in CStdGL.
This is accomplished by caching all existing VAOs per context. If a VAO is
being accessed, it is checked whether that VAO exists in the currently
selected context. If yes, return it, otherwise create a new VAO and return it,
together with a flag that indicates that the VAO needs to be initialized.
The former is not available in a OpenGL 3 core profile, but glGenerateMipmap
is available since OpenGL 3.0, and so is always available when we have a
core profile.
This prevents a crash when an incompatible engine function is used as an
engine callback function.
Unfortunately, this breaks any scripts that have wrong type information in
engine callbacks and only worked because those were ignored.
* all non-diggable materials are now in front of diggable materials
* except: firestone and coal are still in front of rock
At least this change makes it necessary to test every scenario we have if there are any problems with the landscape
Reuse the windows code for this. Both versions had three parts: Enabling
the right menu items, adding the selection-specific ones, and showing the
menu. The second part is now common code, with the platform code in a new
function, since it grew big enough to be worth sharing.
In earlier versions, DrawPatternedCircle was a fairly complicated function.
Nowadays, it just copies pixels in memory, bounded by a circle. Since we
need to convert our surfaces to a format GTK+ can use anyway, combine that
step with the circle boundaries. Also use a cairo surface instead of a
GdkPixbuf. Cairo uses almost the same pixel format, except for
premultiplied alpha. Ignore this for now.
Specifically, GtkGrid. For most cases, this is an increase in lines of
code, but the landscape tools dialog can now be done with just three layout
widgets.
While at it, use a toolbar and move the mode buttons into it, too.
Benedict Etzel (B_E), Phillip Kern (pkern), Kevin Zheng and more
<Special Thanks to Contributors>
Martin Adam (Win), Florian Graier (Nachtfalter), Mark Haßelbusch (Marky), Merten Ehmig (pluto), Benjamin Herr (Loriel), Armin Schäfer, Pyrit, Philip Holzmann (Batman), Alexander Semeniuk (AlteredARMOR), Andriel, Peewee, Oliver Schneider (ker), Fabian Pietsch, Manuel Rieke (MrBeast), Felix Riese (Fungiform), Carl-Philip Hänsch (Carli), Sebastian Rühl, Gurkenglas and many more:
Luchs, Asmageddon, mizipzor, Tim Blume, Apfelclonk, Sven-Hendrik Haase, Lauri Niskanen (Ape), Daniel Theuke (ST-DDT), Russell, Stan, TomyLobo, Clonkine, Koronis, Johannes Nixdorf (mixi), grgecko, Dominik Bayerl, Misty de Meo, Lorenz Schwittmann, hasufell, Jan Heberer, dylanstrategie, Checkmaty, Faby
Also, big thanks to Matthes Bender and all those who contributed to previous Clonk titles for the passion they put into the game and for agreeing to make Clonk open source.
Contributors for OpenClonk 8.0: George Tokmaji (Fulgen), Martin Adam (Win), Merten Ehmig (pluto), Florian Graier (Nachtfalter), Philip Holzmann (Foaly), Dominik Bayerl (Kanibal), Linus Heckemann (sphalerite), Pyrit, Armin Schäfer, Tushar Maheshwari, jok, Tarte, Philip Kern (pkern), Arne Schauf (NativeException), Matthias Mailänder, marsmoon
Previous contributors: Tim Blume, Sven-Hendrik Haase, Carl-Philip Hänsch (Carli), Jan Heberer, Benjamin Herr (Loriel), Lauri Niskanen (Ape), Johannes Nixdorf (mixi), Misty de Meo, Fabian Pietsch, Manuel Rieke (MrBeast), Felix Riese (Fungiform), Sebastian Rühl, Oliver Schneider (ker), Lorenz Schwittmann, Alexander Semeniuk (AlteredARMOR), Daniel Theuke (ST-DDT), Andriel, Apfelclonk, Asmageddon, Checkmaty, Clonkine, dylanstrategie, Faby, grgecko, Gurkenglas, hasufell, Koronis, mizipzor, Peewee, Russell, Stan, TomyLobo
Also thanks to our Linux package maintainers Benedict Etzel (B_E), Linus Heckemann (sphalerite), Philip Kern (pkern), Matthias Mailänder, Julian Ospald (hasufell), Kevin Zheng, and more
Finally, a big thanks to Matthes Bender and all those who contributed to previous Clonk titles for the passion they put into the game and for agreeing to make Clonk open source.
FILE(WRITE"${_pchdir}/${_name}""#ifdef __cplusplus\n#warning Precompiled header not used. Turn off or fix!\n#endif")#Thisfileisaddedsothecc-unitsdon'tstumbleovernotbeingabletoincludethefile
<text>Same as --join if an address is specified. If "update" is specified as an address, this will cause the engine to perform an update check instead.</text>
<text>In multiple places the engine uses ContactAttachment values (a bitmask) to manage the orientation of objects and processes. For example, a vertex of an object can have the <codeid="CNAT">CNAT</code> bit <em>left</em>. If that object has <emlinkhref="definition/defcore.html">ContactCalls</emlink> activated, the engine calls on every contact of that vertex with the landscape the object script function <em>ContactLeft</em>. CNAT values are composed of the following bits:</text>
<text>In multiple places the engine uses ContactAttachment values (a bitmask) to manage the orientation of objects and processes. For example, a vertex of an object can have the <codeid="CNAT">CNAT</code> bit <em>left</em>. If that object has <emlinkhref="definition/properties.html">ContactCalls</emlink> activated, the engine calls on every contact of that vertex with the landscape the object script function <em>ContactLeft</em>. CNAT values are composed of the following bits:</text>
<text>
<table>
<rowh>
@ -40,6 +40,10 @@
<col>CNAT_NoCollision</col>
<col>Extra flag: non-colliding vertex</col>
</row>
<row>
<col>CNAT_PhaseHalfVehicle</col>
<col>Extra flag: Entirely suppress collisions with HalfVehicle</col>
<col>Category of the object. Also see <emlinkhref="definition/category.html">object categories</emlink>.</col>
</row>
<row>
<literal_col>ContactCalls</literal_col>
<col>Integer</col>
<col>0 or 1. If 1, Contactcalls are called in the object script.</col>
</row>
<row>
<literal_col>Width</literal_col>
<col>Integer</col>
@ -65,11 +60,6 @@
<col>Integer</col>
<col>Weight of the object. Rock 10, clonk 50, hut 1000, castle 10000.</col>
</row>
<row>
<literal_col>Components</literal_col>
<col>ID list</col>
<col>Elements from which the object is composed. Uncompleted or half grown objects will only have the respective fraction of the components.</col>
</row>
<row>
<literal_col>SolidMask</literal_col>
<col>6 integers</col>
@ -120,15 +110,10 @@
<col>4 integers</col>
<col>Position of the intake region relative to the object centre.</col>
</row>
<row>
<literal_col>FireTop</literal_col>
<col>Integer</col>
<col>Flame distance to the object's bottom line.</col>
</row>
<row>
<literal_col>Exclusive</literal_col>
<col>Integer</col>
<col>0 or 1. Determines whether the object blocks objects behind it.</col>
<col>0 or 1. Determines whether the object blocks objects behind it. Exclusive objects also block the placement of a construction site at an overlapping location.</col>
</row>
<row>
<literal_col>Line</literal_col>
@ -190,11 +175,6 @@
<col>Integer</col>
<col>0 or 1. The object can be scaled over 100% using DoCon.</col>
</row>
<row>
<literal_col>AttractLightning</literal_col>
<col>Integer</col>
<col>0 or 1. The object attracts lightning.</col>
</row>
<row>
<literal_col>Fragile</literal_col>
<col>Integer</col>
@ -216,7 +196,7 @@
<col>1 - 10. Determines search depth of the pathfinder algorithm (default 1). Warning: higher values may slow down the game. By setting this value you can also enable non-CrewMember objects to use pathfinding when executing commands.</col>
</row>
<row>
<literal_col>NoComponentMass</literal_col>
<literal_col>NoMassFromContents</literal_col>
<col>Integer</col>
<col>0 or 1. If 1, the object's contents is not added to the object's total mass. This can be used to prevent small container objects from turning into killer throwing items.</col>
</row>
@ -280,6 +260,11 @@
<col>Integer</col>
<col>0 or 1. If 1 the object's pathfinding will ignore any transfer zones.</col>
</row>
<row>
<literal_col>HideInCreator</literal_col>
<col>Boolean</col>
<col>false (default) or true. If true, the definition is not shown in the object creator window of the editor. Should be used for internal definitions, libraries, etc.</col>
<text>Graphics of the object. Base graphics, animation phases and a picture for display in menus are stored in a 32 bit picture with transparency channel (PNG format, 32 bit RGBA color, non interlaced).</text>
<text>Graphics of the object. Base graphics, animation phases and a picture for display in menus are stored in a 32 bit picture with transparency channel (PNG format, 32 bit RGBA color, non interlaced). An optional zoom factor for high-resolution graphics can be provided in the '*'-portion of the name.</text>
<text>An optional normal map for the object, where the red, green and blue components in the image correspond to the normal vectors to be used for the lighting of the object. If this file is not present, the normal vector at each pixel points straight into Z direction (outside of the screen).</text>
<text>Objects can also contain alternative sets of graphics which can be selected ingame using the script command <funclink>SetGraphics</funclink>(). The name corresponds to the file name portion following "Graphics". The matching overlay is automatically selected. For more information see <funclink>SetGraphics</funclink>().</text>
<col>Only <emlinkhref="definition/lineconnect.html">line objects</emlink>. Connects <emlinkhref="script/fn/SetAction.html">target object 1</emlink> and <emlinkhref="script/fn/SetAction.html">target object 2</emlink>. If property LineMaxDistance is a nonzero integer, the line breaks when the target objects are further apart than the given distance.</col>
<col>Deprecated. Use <funclink>SetPrototype</funclink> and <funclink>GetPrototype</funclink>.</col>
</row>
<row>
<col><code>Name</code></col>
@ -133,7 +133,7 @@ Stand = {
<rowid="Plane">
<col><code>Plane</code></col>
<col>int</col>
<col>The Object's minor Z-Position. Negative values are behind the landscape, positive values before it. Use 1-399 for stuff behind Clonks, 401-999 for stuff before Clonks, and 1000+ for GUI objects.</col>
<col>The Object's minor Z-Position. Negative values are behind the landscape, positive values before it. Use 1-399 for stuff behind Clonks, 401-999 for stuff before Clonks, and 1000+ for GUI objects. Global particles are on 900.</col>
</row>
<rowid="SolidMaskPlane">
<col><code>SolidMaskPlane</code></col>
@ -168,18 +168,38 @@ Stand = {
<row>
<literal_col>ContactIncinerate</literal_col>
<col>Integer</col>
<col>Probability of incineration by contact: 0 none, or 1 (high) to 5 (low).</col>
<col>Probability of incineration by contact: 0 none, or 1 (high) to 5 (low). Implies MaterialIncinerate.</col>
</row>
<row>
<literal_col>MaterialIncinerate</literal_col>
<col>bool</col>
<col>Incineration when submerged in incendiary material.</col>
</row>
<row>
<literal_col>FireproofContainer</literal_col>
<col>bool</col>
<col>Anything contained in this object does not catch fire when submerged in incendiary material.</col>
</row>
<row>
<literal_col>EditCursorCommands</literal_col>
<col>Array</col>
<col>Array of functions made available in the context menu when right-clicking an object in the editor. Functions may be either strings (like "Explode(20)") or function pointers (like this.Hit). Function pointers are always called by name. Windows only.</col>
<col>Array of functions made available in the context menu when right-clicking an object in the editor. Functions may be either strings (like "Explode(20)") or function pointers (like this.Hit). Function pointers are always called by name.</col>
</row>
<row>
<literal_col>BorderBound</literal_col>
<col>Integer</col>
<col>Bit mask indicating object boundaries: stop at map sides (C4D_Border_Sides), stop at map top (C4D_Border_Top), stop at map bottom (C4D_Border_Sides), stop at object layer boundaries (C4D_Border_Layer). For example BorderBound = C4D_Border_Top | C4D_Border_Bottom.</col>
</row>
<row>
<literal_col>ContactCalls</literal_col>
<col>bool</col>
<col>True or false. If true, <emlinkhref="definition/cnat.html">ContactCalls</emlink> are called in the object script.</col>
</row>
<row>
<literal_col>Components</literal_col>
<col>array</col>
<col>List of definitions and counts specifying the components of an object. Example: Components = {Rock = 1, Wood = 3};</col>
<col>Called in definition context after all definitions have been loaded and before definition properties are frozen. Use this callback to initialize complex definition properties such as EditorProps or dependencies between definitions. Definition() callbacks are performed in descending order of the DefinitionPriority property or 0 if that property is not defined.</col>
</row>
<rowid="Initialize">
<literal_col>Initialize</literal_col>
<col></col>
@ -48,6 +53,11 @@
<col></col>
<col>When the object is removed.</col>
</row>
<rowid="EditorInitialize">
<literal_col>EditorInitialize</literal_col>
<col></col>
<col>Called after Construction and Initialize when the object is placed in the editor.</col>
</row>
<rowid="Hit">
<literal_col>Hit</literal_col>
<col></col>
@ -188,15 +198,15 @@
<col>object by</col>
<col>Called before the object is hit or punched by another object. By returning <code>true</code>, QueryCatchBlow can reject physical blows.</col>
</row>
<rowid="LineBreak">
<literal_col>LineBreak</literal_col>
<rowid="OnLineBreak">
<literal_col>OnLineBreak</literal_col>
<col>int cause</col>
<col>When a line object is broken. cause: 0 by movement, 1 because of a missing or incomplete target object.</col>
</row>
<rowid="BuildNeedsMaterial">
<literal_col>BuildNeedsMaterial</literal_col>
<col>id material_definition, int amount</col>
<col>When the object is building another object and building material is required. The parameters are the type and amount of the first needed material. If this function returns <code>true</code>, no material message is displayed above the object.</col>
<rowid="OnLineChange">
<literal_col>OnLineChange</literal_col>
<col>int cause</col>
<col>When a line object is changed, that is when one of it vertices changed its position.</col>
</row>
<rowid="AttachTargetLost">
<literal_col>AttachTargetLost</literal_col>
@ -333,22 +343,16 @@
<col>int player, int new_team, int old_team</col>
<col>Callback in game goal, rule, and environment objects and in the scenario script. Called when a player has successfully switch from old_team to new_team (see <funclink>SetPlayerTeam</funclink>).</col>
</row>
<rowid="EditCursorSelection">
<literal_col>EditCursorSelection</literal_col>
<col></col>
<col>When object is selected in editor. Use this callback to display extra information for scenario designers.</col>
</row>
<rowid="EditCursorDeselection">
<literal_col>EditCursorDeselection</literal_col>
<col>object next_selection</col>
<col>When object is deselected in editor. Use this callback to hide any information previously shown in EditCursorSelection. If deselection happens due to another object being selected, that object is passed in next_selection.</col>
<rowid="OnCompletionChange">
<literal_col>OnCompletionChange</literal_col>
<col>int old_con, int new_con</col>
<col>Callback in when the completion of the object has changed (see <funclink>GetCon</funclink>, <funclink>DoCon</funclink> and <funclink>SetCon</funclink>).</col>
</row>
<rowid="EditCursorMoved">
<literal_col>EditCursorMoved</literal_col>
<col>int old_x, int old_y</col>
<col>When object is moved in editor. Callback is also done when moved in non-network pause mode. old_x, old_y contains object position before movement.</col>
<text>Properties published to the editor as EditorProps can also be saved automatically by setting the Save property of the EditorProp to a string that serves as an identifier so saved properties can be removed by derived definitions. These properties are atuomatically saved if they are different from their default value. E.g.:</text>
<code>/* Define two properties that can be set in the editor */
// foo is a property with a setter function
local foo = 42;
public func SetFoo(new_foo) { foo = new_foo; return true; }
// bar is just a property without setter
local bar = 23;
local EditorProps = {
foo = { Type="int", Set="SetFoo", Save="Foo" }; // saved as object->SetFoo(value); unless foo is 42.
bar = { Type="int", Save="Bar"; } // saved as object.bar = value; unless bar is 23.
};</code>
<text>By default, effects are not saved in scenarios. To force saving of an effect, define the Fx*SaveScen callback. For example, the fire effect saves itself like this:</text>
<em>Note: For compatibility reasons, the misspelling "Incindiary" is also accepted if (and only if) no value with the correct spelling is set.</em>
</col>
</row>
<row>
<col>Corrode</col>
@ -203,7 +206,7 @@
<row>
<col>OverlayType</col>
<col>Integer</col>
<col>Bit mask for texture calculation on this material. Bit 0 (1): exact (no zoom), bit 1 (2): no texture, bit 2 (4): extra large zoom, bit 3 (8): calculate texture based on gray scale.</col>
<col>Bit mask for texture calculation on this material. Bit 0 (1): exact (no zoom), bit 1 (2): no texture, bit 2 (4): extra large zoom</col>
</row>
<row>
<col>PXSGfx</col>
@ -372,8 +375,11 @@
<col>The background material.</col>
</row>
<row>
<col>Incindiary</col>
<col>All materials to be incinerated.</col>
<col>Incendiary</col>
<col>
All materials that can incinerate objects.
<em>Note: For compatibility reasons, the misspelling "Incindiary" is also accepted.</em>
<col>Defines the attachment of the particles to the calling object. Can be a combination of ATTACH_Front, ATTACH_Back, and ATTACH_MoveRelative. For example <code>ATTACH_Front | ATTACH_MoveRelative</code></col>
<col>Defines the attachment of the particles to the calling object. Can be a combination of ATTACH_Front, ATTACH_Back, and ATTACH_MoveRelative. For example <code>ATTACH_Front | ATTACH_MoveRelative. Non-attached particles are drawn on plane 900 (i.e. before most objects).</code></col>
<col>If true this is a global definition, i.e. not assigned to a particular player. See <emlinkhref="playercontrols.xml#Globals">Global definitions</emlink>.</col>
<col>If true this is a global definition, i.e. not assigned to a particular player. See <emlinkhref="playercontrols.html#Globals">Global definitions</emlink>.</col>
</row>
<row>
<literal_col>Hold</literal_col>
<col>Boolean</col>
<col>If true this command is interpreted as a held command. Such a command remembers whether the control key is pressed and generates another scripting event when it is released. See <emlinkhref="playercontrols.xml#Hold">Held keys</emlink>.</col>
<col>If true this command is interpreted as a held command. Such a command remembers whether the control key is pressed and generates another scripting event when it is released. See <emlinkhref="playercontrols.html#Hold">Held keys</emlink>.</col>
</row>
<row>
<literal_col>RepeatDelay</literal_col>
<col>Integer</col>
<col>Only valid if <em>Hold</em> is true. If greater than 0 then this key generates additional scripting events while pressed every that many number of frames. See <emlinkhref="playercontrols.xml#Repeat">Key repeats</emlink>.</col>
<col>Only valid if <em>Hold</em> is true. If greater than 0 then this key generates additional scripting events while pressed every that many number of frames. See <emlinkhref="playercontrols.html#Repeat">Key repeats</emlink>.</col>
</row>
<row>
<literal_col>InitialRepeatDelay</literal_col>
<col>Integer</col>
<col>If specified then the delay of the first key repeat event can be changed. See <emlinkhref="playercontrols.xml#Repeat">Key repeats</emlink>.</col>
<col>If specified then the delay of the first key repeat event can be changed. See <emlinkhref="playercontrols.html#Repeat">Key repeats</emlink>.</col>
</row>
<row>
<literal_col>DefaultDisabled</literal_col>
<col>Boolean</col>
<col>If true then the command is deactivated in the normal case and needs to be activated by script first. This is useful for commands that are only required in special situations. See <emlinkhref="playercontrols.xml#Deactivate">Deactivated commands</emlink>.</col>
<col>If true then the command is deactivated in the normal case and needs to be activated by script first. This is useful for commands that are only required in special situations. See <emlinkhref="playercontrols.html#Deactivate">Deactivated commands</emlink>.</col>
</row>
<row>
<literal_col>ExtraData</literal_col>
<col>C4ID</col>
<col>Optional ID that is passed to the script function. See <emlinkhref="playercontrols.xml#ExtraData">ExtraData</emlink>.</col>
<col>Optional ID that is passed to the script function. See <emlinkhref="playercontrols.html#ExtraData">ExtraData</emlink>.</col>
</row>
<row>
<literal_col>CoordinateSpace</literal_col>
@ -94,7 +94,7 @@
</row>
<row>
<literal_col>Script</literal_col>
<col>Execution of the script function <em>PlayerControl</em>. See <emlinkhref="playercontrols.xml#Script">Script callbacks</emlink>. (Default value)</col>
<col>Execution of the script function <em>PlayerControl</em>. See <emlinkhref="playercontrols.html#Script">Script callbacks</emlink>. (Default value)</col>
</row>
<row>
<literal_col>ZoomIn</literal_col>
@ -184,17 +184,17 @@
<row>
<literal_col>Key</literal_col>
<col>String</col>
<col>Specifies the key(s) of this mapping or a reference to another mapping. See <emlinkhref="playercontrols.xml#Keys">Key mappings</emlink>.</col>
<col>Specifies the key(s) of this mapping or a reference to another mapping. See <emlinkhref="playercontrols.html#Keys">Key mappings</emlink>.</col>
</row>
<row>
<literal_col>ComboIsSequence</literal_col>
<col>Boolean</col>
<col>If true then multiple keys are taken as a sequence, i.e. they need to be pressed one after the other instead of all at the same time. See <emlinkhref="playercontrols.xml#Keys">Key mappings</emlink>.</col>
<col>If true then multiple keys are taken as a sequence, i.e. they need to be pressed one after the other instead of all at the same time. See <emlinkhref="playercontrols.html#Keys">Key mappings</emlink>.</col>
</row>
<row>
<literal_col>Control</literal_col>
<col>String</col>
<col>Command that is combined with this mapping. The name should be equivalent to the <em>Identifier</em> of a command defined in a <emlinkhref="playercontrols.xml#ControlDef">[ControlDef]</emlink>.</col>
<col>Command that is combined with this mapping. The name should be equivalent to the <em>Identifier</em> of a command defined in a <emlinkhref="playercontrols.html#ControlDef">[ControlDef]</emlink>.</col>
</row>
<row>
<literal_col>GUIName</literal_col>
@ -239,11 +239,11 @@
</row>
<row>
<literal_col>Hold</literal_col>
<col>The key changes the state of the command linked to to be held even if the key itself is pressed only shortly. Only valid if the <em>Hold</em> attribute is set for the command. This state remains until a corresponding mapping with trigger mode <em>Release</em> is being pressed. See <emlinkhref="playercontrols.xml#Hold">Held keys</emlink>.</col>
<col>The key changes the state of the command linked to to be held even if the key itself is pressed only shortly. Only valid if the <em>Hold</em> attribute is set for the command. This state remains until a corresponding mapping with trigger mode <em>Release</em> is being pressed. See <emlinkhref="playercontrols.html#Hold">Held keys</emlink>.</col>
</row>
<row>
<literal_col>Release</literal_col>
<col>The key removes the held state. A key can have both Hold and Release set to toggle between the two states. See <emlinkhref="playercontrols.xml#Hold">Held keys</emlink>.</col>
<col>The key removes the held state. A key can have both Hold and Release set to toggle between the two states. See <emlinkhref="playercontrols.html#Hold">Held keys</emlink>.</col>
</row>
<row>
<literal_col>AlwaysUnhandled</literal_col>
@ -273,7 +273,7 @@
return true;
}</code>
<text>most commands (except for asynchronous commands in the player menu) call a global script function:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)</code>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)</code>
<text>For an explanation of the parameters see <funclink>PlayerControl</funclink>. Amongst others, the function receives the calling player in player as well as the command to be executed in control.</text>
<text>As a simple example let's assume that in the global <em>PlayerControls.txt</em> the following command has been defined:</text>
<code>[ControlDefs]
@ -293,11 +293,11 @@
Control=Jump
Priority=50</code>
<text>This defines a Jump key and the corresponding standard mapping on the keyboard for the first player. The following script is used to handle the control:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)
{
// Which command has been issued?
// The constant CON_Jump has been declared automatically through the definition in PlayerControls.txt
if (control == CON_Jump &&!release)
if (control == CON_Jump &&state == CONS_Down)
{
// pressed the jump button. The clonk selected by the player shall jump
var player_clonk = GetCursor(player);
@ -319,17 +319,17 @@
GUIDesc=Going underground
ExtraData=Shovel</code>
<text>Let shovel be the ID of a shovel object. In the global script there could be the following, generic handling for unknown commands, for example:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)
{
// Handling of known controls
// [...]
// control with own handling
if (control_extra) return control_extra->PlayerControl(player, control, x, y, strength, repeat, release);
if (control_extra) return control_extra->PlayerControl(player, control, x, y, strength, repeat, state);
// unkown control
return false;
}</code>
<text>And in the script of the shovel:</text>
<code>func PlayerControl(int player, int control, int x, int y, int strength, bool repeated, bool release)
<code>func PlayerControl(int player, int control, int x, int y, int strength, bool repeated, int state)
{
// Handling of known controls
// Control dig directly in the shovel
@ -351,8 +351,9 @@
<ul>
<li>When released they also generate <funclink>PlayerControl</funclink> calls in the script with the <em>Release</em> flag set.</li>
<li>Mappings can emulate permanent key presses using the <em>Hold</em>/<em>Release</em> flags.</li>
<li><emlinkhref="playercontrols.xml#Repeat">Key repeats</emlink> are generated.</li>
<li><emlinkhref="playercontrols.html#Repeat">Key repeats</emlink> are generated.</li>
<li>The held state of the key can be queried in the script via <funclink>GetPlayerControlState</funclink>.</li>
<li>If the command is bound to an analog stick or trigger on a controller, every change in position causes in a call to PlayerControl() with state = CONS_Moved.</li>
</ul>
</text>
<text>A good example for this functionality is a directional command:</text>
@ -362,7 +363,7 @@
GUIDesc=Walk left
Hold=1</code>
<text>In the script the direction is transferred to the Clonk:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)
{
if (control == CON_Left) return UpdateControlDir(player);
<col>The scenario will only load if the player gained this password in another scenario. See script function <funclink>GainMissionAccess</funclink>().</col>
<col>The scenario will only load if the player gained this password in another scenario. See script function <funclink>GainScenarioAccess</funclink>().</col>
</row>
<row>
<col>Secret</col>
<col>bool</col>
<col>Bool</col>
<col>If true and MissionAccess is set, the scenario is invisible in the scenario selection list if the player does not have the required password access.</col>
</row>
<row>
@ -100,6 +100,11 @@
<col>Data type</col>
<col>Description</col>
</rowh>
<row>
<col>Mode</col>
<col>String</col>
<col>General game mode of this scenario. Used by network and league servers to determine which league to host the game in. Currently suggested identifiers are: Melee, Parkour, Settlement, Defense. Strings should be valid identifiers.</col>
</row>
<row>
<col>Rules</col>
<col>ID list</col>
@ -117,9 +122,14 @@
</row>
<row>
<col>FoWEnabled</col>
<col>Integer</col>
<col>Bool</col>
<col>0 or 1. If 0, FoW is disabled, and the whole landscape is visible. Default 1.</col>
</row>
<row>
<col>EvaluateOnAbort</col>
<col>Bool</col>
<col>If enabled, the game will be evaluated even when aborted by the player. This is intended for scenarios like Tower of Despair that save progress in players. Default false.</col>
</row>
</table>
</text>
<text>
@ -243,7 +253,7 @@
<row>
<literal_col>AutoScanSideOpen</literal_col>
<col>Integer</col>
<col>0 or 1. If 1, LeftOpen and RightOpen will be set automatically depending on the landscape at game start.</col>
<col>0, 1, or 2. If 1, the left and right borders are closed if the corresponding map pixel in the left or right row has non-sky foreground or background and open otherwise. If 2, it only checks the background.</col>
</row>
<row>
<literal_col>MapWidth</literal_col>
@ -340,6 +350,11 @@
<col>Integer</col>
<col>0 or 1. If 1, all landscape chunks are drawn flat when the map is zoomed to draw the landscape. Set this while drawing a static map in console mode to fix small gaps of lower order materials hidden behind materials of chunky shape.</col>
</row>
<row>
<literal_col>Secret</literal_col>
<col>Bool</col>
<col>Whether to hide the map from <code><funclink>NO_OWNER</funclink></code> viewports (e.g. observers not following a player in network rounds)</col>
<col>int player, int x, int y, object base, int team, id extra_data</col>
<col>Called after when a new player joins the game. At this point, the clonks, materials, structures etc. are already placed at the position given in the <emlinkhref="scenario/scenario.html#SektionenPlayer1Player2Player3Player4">Scenario.txt</emlink>. <code>x</code> and <code>y</code> specify the starting position of the player, <code>base</code> is the player's base (if any), <code>team</code> denotes the team of the player. For <code>extra_data</code>, see <funclink>CreateScriptPlayer</funclink></col>
</row>
<rowid="InitializePlayers">
<literal_col>InitializePlayers</literal_col>
<col></col>
<col>Called after all initial players joined. Can be used e.g. to start intros.</col>
<text>With #appendto, you can modify an existing object defintion script without changing the original file. For example, a scenario could change flints to cause bigger explosions, without having to duplicate the entire flint in the scenario.</text>
<hid="Syntax">Declaration</h>
<code>#appendto [id]</code>
<text>A script can append itself to one or multiple existing scripts using the <code>#appendto</code> directive. Functions of the same name will overload functions in the target script. The original overloaded functions can still be called using <emlinkhref="script/fn/inherited.html">inherited</emlink>. #included scripts are not appended with #append, but #appended scripts are included by #include.</text>
<text>A script can append itself to one or multiple existing scripts using the <code>#appendto</code> directive. Such script needs to be placed in System.ocg directory. Functions of the same name will overload functions in the target script. The original overloaded functions can still be called using <emlinkhref="script/fn/inherited.html">inherited</emlink>. #included scripts are not appended with #append, but #appended scripts are included by #include.</text>
<code>#appendto *</code>
<text>Appending to <code>*</code> will append this script to all definitions.</text>
<text>A script can contain multiple #appendto directives. It is always compiled with the original script. This is of interest whenever local variables or functions from the appended script are used.</text>
<hid="Example">Example</h>
<code>#appendto WindBag
// This function will be "overwritten" in the original windbag.
// You can however call the original function by calling <funclink>_inherited</funclink>(...)
// You'll find this quite often in other scenarios. Just take a look at other
<text>The magic spell object exists until the spell has ended and then makes the clonk visible again. Also, if the spell object is deleted for other reasons (e.g. a scenario section change), the clonk is made visible in the Destruction callback (if this wasn't so, the clonk would remain invisible for ever). Also there is a Timer (defined in the DefCore) called every second. Notice you couldn't just have a single timer call to mark the end of the spell because timer intervals are marked in the engine beginning with the start of the round and you wouldn't know at what point within an engine timer interval the spell would start.</text>
<text>However, there are some problems with this implementation: for example, the magician can not cast a second invisibility spell while he's already invisible - the second spell would have practically no effect, because the end of the first spell would make the clonk visible again. The spell script would have to do some special handling for this case - but not only for multiple invisibility spells, but also for any other spell or script that might affect visibility or coloration of the clonk. Even if this spell would remember the previous value e.g. for coloration it could not handle a situation in which other scripts change the color of their own in the middle of the spell. The same problems occur when multiple scripts modify temporary clonk physcials such as jumping, walking speed, fight strength or visibility range, energy, magic energy etc. Using effects, these conflicts can be avoided.</text>
<hid="Usage">Application</h>
<text>Effects are created using <funclink>AddEffect</funclink> and removed with <funclink>RemoveEffect</funclink>. If an effect was successfully created, the callback Fx*Start is made (* is replaced with the effect name). Depending on the parameters, there can also be an Fx*Timer call for continuous activity such as casting sparks, adjusting energy etc. Finally, when the effect is deleted, the callback Fx*Stop is made. Now, the invisibility spell implemented using effects:</text>
<text>Effects are created using <funclink>CreateEffect</funclink> and removed with <funclink>RemoveEffect</funclink>. If an effect was successfully created, the callback <emlinkhref="script/Effects.html#Construction">Construction</emlink> is made. Depending on the parameters, there can also be an <emlinkhref="script/Effects.html#TimerCallback">Timer</emlink> call for continuous activity such as casting sparks, adjusting energy etc. Finally, when the effect is deleted, the callback <emlinkhref="script/Effects.html#Destruction">Destruction</emlink> is made.</text>
<text>Now, the invisibility spell implemented using effects:</text>
<text>In this case, the magic spell object only starts the effect, then deletes itself immediately. The engine ensures that there are no conflicts with multiple effects modifying the visibility: effects are stored in a stack which ensures that effects are always removed in the opposite order of their addition. For this, there are a couple of extra Start and Stop calls to be made which are explained in detail later.</text>
<text>This effects does not have a timer function. It does, however, define a timer interval of 1111 which will invoke the standard timer function after 1111 frames which will delete the effect. Alternatively, you could define a timer function as such:</text>
<code>func FxInvisPSpellTimer()
<code>Timer = func()
{
// return value of -1 means that the effect should be removed
return -1;
// return value of -1 means that the effect should be removed
return -1;
}</code>
<text>To store the previous status of the target object, properties of the effect are used. This is necessary because in this case the effect callbacks do not have any object script context. So you cannot access any object local variables in the effect callbacks - remember that the magic spell object which has created the effect is already deleted. If you require an object context in the effect callbacks you can specify one in <funclink>AddEffect</funclink>(). In that case, effect callbacks would be in object local context and the effect would automatically be deleted if the target object is destroyed.</text>
<text>To store the previous status of the target object, properties of the effect are used. This way effects are independant of other objects and effects - remember that the magic spell object which has created the effect is already deleted. If you need to call functions in the context of the target object or other objects, use <code>-></code>.</text>
<hid="Priorities">Priorities</h>
<text>When creating an effect you always specify a priority value which determines the effect order. The engine ensures that effects with lower priority are added before effects with a higher priority - even if this means deleting an existing effect of higher priority. So if one effect colors the clonk green and another colors the clonk red, the result will be that of the effect with higher priority. If two effects have the same priority, the order is undefined. However, it is guaranteed that effects added later always notify the Fx*Effect callback of the same priority.</text>
<text>In the case of the red and green color, one effect could also determine the previous coloring and then mix a result using ModulateColor. But priorities also have another function: an effect of higher priority can prevent the addition of other effects of lower priority. This is done through the Fx*Effect callback. If any existing effect reacts to this callback with the return value -1, the new effect is not added (the same applies to the Start callback of the effect itself). Here an example:</text>
<text>When creating an effect you always specify a priority value which determines the effect order. The engine ensures that effects with lower priority are added before effects with a higher priority - even if this means deleting an existing effect of higher priority. So if one effect colors the clonk green and another colors the clonk red, the result will be that of the effect with higher priority. If two effects have the same priority, the order is undefined. However, it is guaranteed that effects added later always notify the <code>Effect</code> callback of the same priority.</text>
<text>In the case of the red and green color, one effect could also determine the previous coloring and then mix a result using ModulateColor. But priorities also have another function: an effect of higher priority can prevent the addition of other effects of lower priority. This is done through the <code>Effect</code> callback. If any existing effect reacts to this callback with the return value -1, the new effect is not added (the same applies to the Start callback of the effect itself). Here an example:</text>
if (!temporary) target-><funclink>Extinguish</funclink>();
return true;
}
func FxBanBurnPSpellEffect(string new_name)
{
// block fire
if (<funclink>WildcardMatch</funclink>(new_name, "*Fire*")) return -1;
// everything else is ok
return 0;
}</code>
<text>This effect makes the clonk fire-proof for 30 seconds. The effect is implemented without any Timer or Stop callbacks as the complete functionality is achieved by simply blocking other effects which might have "Fire" as part of their name. This especially applies to the engine internal fire which has exactly the name "Fire". Of course, you could still add a Timer callback for graphic effects so the player can see that his clonk is immune. Also, you could create special visual effects when preventing incineration in FxBanBurnPSpellEffect. For the like:</text>
local BanBurnPSpell = new Effect {
Construction = func()
{
// On start of the effect: extinguish clonk
Target-><funclink>Extinguish</funclink>();
},
Effect = func(string new_name)
{
// block fire
if (<funclink>WildcardMatch</funclink>(new_name, "*Fire*")) return -1;
// everything else is ok
return 0;
}
};</code>
<text>This effect makes the clonk fire-proof for 30 seconds. The effect is implemented without any Timer or Stop callbacks as the complete functionality is achieved by simply blocking other effects which might have "Fire" as part of their name. This especially applies to the engine internal fire which has exactly the name "Fire". Of course, you could still add a Timer callback for graphic effects so the player can see that his clonk is immune. Also, you could create special visual effects when preventing incineration in <code>Effect</code>. For the like:</text>
if (var3 &&<funclink>GetType</funclink>(var3) == <funclink>C4V_C4Object</funclink>) var3-><funclink>Extinguish</funclink>();
// block fire
return -1;
}</code>
<text>This would even delete all burning objects which would otherwise incinerate the target object. The type check for var3 avoids possible conflicts with other "Fire" effects that might have differing parameters. Obviously, conflict situations like this should be avoided at all cost.</text>
<text>The following table contains general guidelines for priorities in effects of the original pack:</text>
if (!temporary) target-><funclink>Message</funclink>("%s gets an extra life", target-><funclink>GetName</funclink>());
return true;
}
local ReincarnationPSpell = new Effect {
Construction = func() {
// Only at the first start: message
Target-><funclink>Message</funclink>("%s gets an extra life", Target-><funclink>GetName</funclink>());
return true;
},
func FxReincarnationPSpellStop(object target, proplist effect, int reason, bool temporary)
{
// only when the clonk died
if (reason != 4) return true;
// the clonk has already been resurrected
if (target-><funclink>GetAlive</funclink>()) return -1;
// resurrect clonk
target-><funclink>SetAlive</funclink>(true);
// give energy
target-><funclink>DoEnergy</funclink>(100);
// message
target-><funclink>Message</funclink>("%s has been resurrected.", target-><funclink>GetName</funclink>());
func Stop(int reason, bool temporary) {
// only when the clonk died
if (reason != 4) return true;
// the clonk has already been resurrected
if (Target-><funclink>GetAlive</funclink>()) return -1;
// resurrect clonk
Target-><funclink>SetAlive</funclink>(true);
// give energy
Target-><funclink>DoEnergy</funclink>(100);
// message
Target-><funclink>Message</funclink>("%s has been resurrected.", Target-><funclink>GetName</funclink>());
// remove
return true;
}</code>
// remove
return true;
}
};</code>
<text>This effect reanimates the clonk as many times as he has cast the reanimation spell.</text>
<hid="GlobalEffects">Global Effects</h>
<text>Global effects are effects that are not bound to any target object. With global effects, too, priorities are observed and temporary Add/Remove calls might be necessary to ensure order. Simply imagine all global effects are attached to an imaginary object. Global effects are accessed whenever you specify <code>nil</code> for the target object.</text>
<text>There are two global effect types: Scenerio effects and global effects. They are bound to the <code>Scenario</code> and <code>Global</code> proplists. With these effects, too, priorities are observed and temporary Add/Remove calls might be necessary to ensure order.</text>
<text>This can be used to make changes to gravity, sky color, etc. Here's an example for a spell that temporarily reduces gravity and then resets the original value:</text>
<col>Of the <ahref="#TimerCallback">Timer callback</a>.</col>
</row>
<row>
<col>int</col>
<col><code>Time</code></col>
<col>int</col>
<col>The age of the effect in frames, used for the <ahref="#TimerCallback">Timer callback</a>. Can be changed.</col>
</row>
<row>
<col>proplist</col>
<col><code>CommandTarget</code></col>
<col>Either the command object or the command definition, depending on which is used.</col>
<col>proplist</col>
<col><code>nil</code> when created by <funclink>CreateEffect</funclink>, as the effect gets the callbacks itself. When created by <funclink>AddEffect</funclink> either the command object or the command definition, depending on which is used.</col>
</row>
<row>
<col><code>Target</code></col>
<col>proplist</col>
<col>The object the effect belongs to, or the proplists <code>Scenario</code> or <code>Global</code> for scenario and global effects.</col>
</row>
</table>
<hid="UserCallbacks">User Defined Properties</h>
@ -488,19 +488,19 @@ global func FxExplodeOnDeathCurseStop(object target, proplist effect, int reason
</row>
</table>
</text>
<text>Warning: as function names may not be more than 100 characters in length (and you will lose oversight eventually), you should not stuff too much information into the effect name. Effect names are case sensitive. Also, you should avoid using any of these identifiers in your effect names if your effect doesn't have anything to do with them.</text>
<text>Effect names are case sensitive. Also, you should avoid using any of these identifiers in your effect names if your effect doesn't have anything to do with them.</text>
<hid="CBRef">Callback Reference</h>
<part>
<text>The following callbacks are made by the engine and should be implemented in your script according to necessity. * is to be replaced by your effect name.</text>
<h>Fx*Start</h>
<text><code>int Fx*Start (object target, proplist effect, int temporary, any var1, any var2, any var3, any var4);</code></text>
<text>Called at the start of the effect. target is the target object of the effect. <code>effect</code> is the effect itself. <code>effect</code> can be used to manipulate the effect, for example with <code>effect.Interval=newinterval</code>.</text>
<text>The following callbacks are made by the engine and should be implemented in your effect prototype as necessary.</text>
<h>Start</h>
<text><code>int Start (int temporary, any var1, any var2, any var3, any var4);</code></text>
<text>Called at the start of the effect. <code>this</code> is the effect itself. It can be used to manipulate the effect, for example with <code>this.Interval=newinterval</code>.</text>
<text>In normal operation the parameter temporary is 0. It is 1 if the effect is re-added after having been temporarily removed and 2 if the effect was temporarily removed and is now to be deleted (in this case a Remove call will follow).</text>
<text>If temporary is 0, var1 to var4 are the additional parameters passed to <funclink>AddEffect</funclink>().</text>
<text>If temporary is 0 and this callback returns -1 the effect is not created and the corrsponding <funclink>AddEffect</funclink>() call returns 0.</text>
<h>Fx*Stop</h>
<text><code>int Fx*Stop (object target, proplist effect, int reason, bool temporary);</code></text>
<text>When the effect is temporarily or permanently removed. target again is the target object and <code>effect</code> the effect itself.</text>
<text>If temporary is 0, var1 to var4 are the additional parameters passed to <funclink>CreateEffect</funclink>().</text>
<text>If temporary is 0 and this callback returns -1 the effect is not created and the corrsponding <funclink>CreateEffect</funclink>() call returns <code>nil</code>.</text>
<text>When the effect is temporarily or permanently removed. <code>this</code> is the effect itself.</text>
<text>reason contains the cause of the removal and can be one of the following values:</text>
<text>
<table>
@ -537,26 +537,34 @@ global func FxExplodeOnDeathCurseStop(object target, proplist effect, int reason
</table>
</text>
<text>The effect can prevent removal by returning -1. This will not help, however, in temporary removals or if the target object has been deleted.</text>
<hid="TimerCallback">Fx*Timer</h>
<text><code>int Fx*Timer (object target, proplist effect, int time);</code></text>
<text>Periodic timer call, if a timer interval has been specified at effect creation. target and <code>effect</code> as usual.</text>
<hid="FxConstructionCallback">Construction</h>
<text><code>int Construction (any var1, any var2, any var3, any var4);</code></text>
<text>Called when the effect is first created, before it is started. The parameters <code>var1</code> to <code>var4</code> are passed through from <funclink>CreateEffect</funclink>.</text>
<text>Callback when the effect is removed. <code>reason</code> is the same as in the preceding <code>Stop</code> call, see above.</text>
<text>The return value is ignored.</text>
<hid="TimerCallback">Timer</h>
<text><code>int Timer (int time);</code></text>
<text>Periodic timer call, if a timer interval has been specified at effect creation.</text>
<text>time specifies how long the effect has now been active. This might alternatively be determined using effect.Time.</text>
<text>If this function is not implemented or returns -1, the effect will be deleted after this call.</text>
<h>Fx*Effect</h>
<text><code>int Fx*Effect (string new_name, object target, proplist effect, any var1, any var2, any var3, any var4);</code></text>
<text>A call to all effects of higher priority if a new effect is to be added to the same target object. new_name is the name of the new effect; <code>effect</code> is the effect being called.</text>
<h>Effect</h>
<text><code>int Effect (string new_name, any var1, any var2, any var3, any var4);</code></text>
<text>A call to all effects of higher priority if a new effect is to be added to the same target object. new_name is the name of the new effect; <code>this</code> is the effect being called.</text>
<text>Warning: the new effect is not yet properly initialized and should not be manipulated in any way. Especially the priority field might not yet have been set.</text>
<text>This function can return -1 to reject the new effect. As the new effect might also be rejected by other effects, this callback should not try to add effects or similar (see gravitation spell). Generally you should not try to manipulate any effects during this callback.</text>
<text>Return -2 or -3 to accept the new effect. As long as the new effect is not rejected by any other effect, the Fx*Add call is then made to the accepting effect, the new effect is not actually created, and the calling AddEffect function returns the effect index of the accepting effect. The return value -3 will also temporarily remove all higher prioriy effects just before the Fx*Add callback and re-add them later.</text>
<text>var1 bis var4 are the parameters passed to <funclink>AddEffect</funclink>()</text>
<h>Fx*Add</h>
<text><code>int Fx*Add (object target, proplist effect, string new_name, int new_timer, any var1, any var2, any var3, any var4);</code></text>
<text>Callback to the accepting effect if that has returned -2 or -3 to a prior Fx*Effect call. <code>effect</code> identifies the accepting effect to which the consequences of the new effect will be added; target is the target object (0 for global effects).</text>
<text>Return -2 or -3 to accept the new effect. As long as the new effect is not rejected by any other effect, the <code>Add</code> call is then made to the accepting effect, the new effect is not actually created, and the calling <funclink>CreateEffect</funclink> function returns the accepting effect. The return value -3 will also temporarily remove all higher prioriy effects just before the <code>Add</code> callback and re-add them later.</text>
<text>var1 bis var4 are the parameters passed to <funclink>CreateEffect</funclink>()</text>
<h>Add</h>
<text><code>int Add (string new_name, int new_timer, any var1, any var2, any var3, any var4);</code></text>
<text>Callback to the accepting effect if that has returned -2 or -3 to a prior <code>Effect</code> call. <code>this</code> identifies the accepting effect to which the consequences of the new effect will be added.</text>
<text>new_timer is the timer interval of the new effect; var1 to var4 are the parameters from AddEffect. Notice: in temporary calls, these parameters are not available - here they will be 0.</text>
<text>If -1 is returned, the accepting effect is deleted also. Logically, the calling AddEffect function will then return -2.</text>
<h>Fx*Damage</h>
<text><code>int Fx*Damage (object target, proplist effect, int damage, int cause);</code></text>
<text>Every effect receives this callback whenever the energy or damage value of the target object is to change. If the function is defined, it should then return whether to allow the change.</text>
<text>If -1 is returned, the accepting effect is deleted also. Logically, the calling <funclink>CreateEffect</funclink> function will then return <code>nil</code>.</text>
<h>Damage</h>
<text><code>int Damage (int damage, int cause, int by_player);</code></text>
<text>Every effect receives this callback whenever the energy or damage value of the target object is to change. If the function is defined, it should then return the damage to be done to the target.</text>
<textid="damagecause">This callback is made upon life energy changes in living beings and damage value changes in non-livings - but not vice versa. cause contains the value change and reason:</text>
<text>
<table>
@ -639,7 +647,7 @@ global func FxExplodeOnDeathCurseStop(object target, proplist effect, int reason
<text>There are the following functions for manipulation of effects:</text>
<text>
<ul>
<li><funclink>AddEffect</funclink>() - for effect creation</li>
<li><funclink>CreateEffect</funclink>() - for effect creation</li>
<li><funclink>RemoveEffect</funclink>() - for effect removal</li>
<li><funclink>GetEffect</funclink>() - to search for effects</li>
<li><funclink>GetEffectCount</funclink>() - for effect counting</li>
<text>Finds a random position in the shape and returns it as properties x and y in the supplied proplist. The return value indivates whether a point could be found.</text>
<text>The parameter max_tries indicates how many times the algorithm tries to find a point within the shape. The function is guaranteed to succeed for non-empty base shapes (i.e. rectangle and circle) as well as combined shapes on a single try. However a stochastic approach is used for intersection and subtraction shapes where random points are queried from one of the sub-shapes and subsequently checked against the other sub-shapes.</text>
<text></text>
<code>bool GetArea();</code>
<text>Returns the area covered by the shape in squared pixels.</text>
<text></text>
<code>proplist GetBoundingRectangle();</code>
<text>Returns a rectangular shape that includes at least the whole shape used as calling context.</text>
<desc>Target object for the effect. If <code>nil</code>, a global effect is created.</desc>
<desc>Target object for the effect. If <code>nil</code>, <code>Global</code> is used, but the target parameter of the callbacks will get <code>nil</code>.</desc>
<optional/>
</param>
<param>
@ -74,6 +75,7 @@
<remark>For examples and more information see the <emlinkhref="script/Effects.html">effects documentation</emlink>.</remark>
Shader category or shader name the slices are added to. Known categories:
<table>
<rowh>
<col>Category</col>
<col>Description</col>
</rowh>
<row>
<col>Common</col>
<col>Applies to everything.</col>
</row>
<row>
<col>Object</col>
<col>Applies to all objects and sprites.</col>
</row>
<row>
<col>Landscape</col>
<col>Applies to the landscape.</col>
</row>
</table>
</desc>
</param>
<param>
<type>string</type>
<name>shader</name>
<desc>The GLSL shader code.</desc>
</param>
</params>
</syntax>
<desc>Adds shader slices to a category of shaders or to a single shader. Returns an identifier for removal.</desc>
<remark>
Consider using built-in functions such as <funclink>SetGamma</funclink>, <funclink>SetMatAdjust</funclink>, or <funclink>SetClrModulation</funclink> for changing colors instead of writing a custom shader.
<desc>Object category: the object moves parallax with respect to the landscape. This means that the apparent object position changes depending on the scroll position of the viewport. This can be used to have objects apparently moving in the far background or to create status overlays.<br/>Parallax deviation from the normal location is specified in percent and stored in an array in the <emlinkhref="definition/properties.html#Parallaxity"><code>Parallaxity</code> property</emlink> of the object (<code>Parallaxity[0]</code> for horizontal, <code>Parallaxity[1]</code> for vertical deviation). This means for normal location these two values should be 100. A value of 0 will lock the object to the viewport. For parallax background object use values between 0 and 100. Object positions can also be negative values. Those objects will then be aligned with the right or bottom edge of the screen respectively.</desc>
<desc>Objects with this category do not move. This is useful for all kinds of stuff, like making sure rule objects don't fall out of the landscape.</desc>
<desc>Data type: Definition. Definitions are a special type of proplist, and this data type is used for distinguishing definitions from proplists.</desc>