UnrealScript Quirks
This page lists all those little annoying things that you wouldn't expect UnrealScript to do, but it does. Especially those things that are unintuitive or cause very hard to diagnose problems.
Logging Rotators
When you log a rotator, its values automatically get wrapped to 0-65535, even if they're outside that range. Log lies!
Up is left Padawan
The Unreal World uses a Left-Handed Coordinate System. This means that the y-axis goes the 'wrong way'. Quite unreal.
Physics changes take a tick
If you decide to change a Pawn's physics, don't then write code assuming the change happens immediately. A tick? has to pass before the change registers.
Foxpaw: Can you elaborate on what exactly is meant by this?
dataangel: Sure. If you use SetPhysics on something (actually come to think of it this probably isn't just for pawn) the physics doesn't actually change until one game tick has passed (one iteration through the main game loop, look at the tick funtion in Actor/Methods on the wiki). I'm not sure if logging Pawn.Physics will show the new physics or the old one, but if you try and call some native function that only works when the pawn is in a certain physics, it'll treat the pawn as if it had the old physics until the next tick.
Simulated
The simulated keyword means that a function CAN run on a client, not that it will. This is not a magic fix, which will suddenly make your code run on the network. See simulated function.
UCC GPF
Making your class DependsOn a class that ucc can't find will cause it to fault. No, it does not give you a nice descriptive error. It crashes and laughs at you.
5 meters is 5 meters, except when it's not
The Karma functions and the rest of Unreal use completely different scales. Yes, even though it is the same engine. Be sure to convert between the two. See Unreal Unit.
Solid Snake: This has been noted many times before. All of the Karma references will also mention that the units used between Karma and Unreal are different on a linear scale.
There is no include
There's no way for you to add your own global functions without purchasing the engine and editing object.uc yourself. You can get very very ugly long static functions by declaring a class, making the functions static, then referencing them like so: class'myClass'.static.myfunc.
El Muerte: Actually, there is an include, but it does not work as you expect and it has some quirks. The include is a macro:
#include Path/Relative/To/Package.inc
This will include the file ../Package/Path/Relative/To/Package.inc
AS IS. However, this will screw up the linecount, so if that file contains 6 lines the compile might claim a error on the n'th line you should look at the (n-6)th line in your code. Ofcourse this option doesn't solve the issue that you can't define global functions (you can't do that in Java either, so who cares). It's best to avoid the #include directive.
However, there is a way to create non static global functions. This requires you to create an class containing these global non static functions. Create an include file like this:
// include this file before the first function declaration var MyGlobalActor mgo; /** call this function in PreBeginPlay */ function InitGlobalObject() { forearch AllActors(class'MyGlobalActor', mgo) break; if (mgo == none) mgo = spawn(class'MyGlobalActor', Level); }
Ofcourse this won't solve all your problems, but in some cases it might help you a bit.
Note: when you are creating a new gametype, you're better of creating a new GRI class that contains your new global functions.
Initializing bloat
You can't declare a variable and initialize it in the same line, unlike most other programming languages. UCC is not very kind about this either. It will give you all sorts of cryptic errors depending on where you attempt this. I am almost certain there is code in ucc to explicitly prevent it from giving you a clear error message for this by selecting one at random.
Vectors and Rotators on the Fly... sort of
The builtin vect(x,y,z) and rot(Pitch,Yaw,Roll) operators for creating vectors and rotators on the fly may seem useful. But then try to pass anything but constants. rot(0, 200, 50) will work but rot(myvar, 300, 200) will not. Luckily, ucc will print out a random error message to assist you. Which will lead you for some arbitrary reason thought of at Epic to do this:
local rotator temp; temp.Pitch = myvar; temp.Yaw = 300; temp.Roll = 200;
Foxpaw: The reason why Epic did this is very simple. Rot(100,0,0) is a constant, like "I love strings" or 5. It's syntax makes it look like a function, but it isn't one. Constants are considerably faster at runtime than evaluating a function with constant arguments.
dataangel: Nor though would it have been terribly difficult for them to make it a native function that works with variables and only optimize for constants when you specify all constants. Then it would act intuitively But you're right and that's not the point. I'll change the description above to explain that.
Solid Snake: I think it's like when you attempt to do this, dynamicarray.length++;. The syntax is correct and UCC will compile it, but you can't do that.
Log's Double Dishonesty
Not only does log report rotators incorrectly, it'll also truncate your float values. See also: Baudrillard.
DesiredRotation Undesirable
If you want to use DesiredRotation for actors with physics other than PHYS_Rotating or PHYS_Projectile, you're out of luck. No matter what you do the engine will not do the rotation for you. You'll have to come up with your own system.
Not all strings are in code
If there's a string for your mod you want to override, and you can't find it anywhere in the .uc files, chances are for localization reasons it's stored in the INT files. Search those.
Solid Snake: That makes no sense. You define the contents of the INT or other language files inside UC file. You can't randomly just put a variable definition inside a language file and get away with it. Thus, you need to say that rather than trying to find the definition of the variable string or whatever else, look in the language file, although the variable itself is declared in the UC file.
dataangel: Eh, when I say string I don't mean the variable declaration. I mean the actual string literal. When people see "The game will begin in 3..2..1.." and stuff like that they type that string in and search their .uc files and wonder why there are no results.
Related Topics
Discussion
dataangel: I'm sure I've missed a ton, but these were the quirks I remembered and had caused me the most time wasted today Please add.