blankart/extras/ACS/doc/examples/ZDACS.c
2025-01-29 01:07:15 -05:00

171 lines
5.5 KiB
C

//-----------------------------------------------------------------------------
//
// Example C code for GDCC.
//
//-----------------------------------------------------------------------------
// Any project targeting ZDoom or other ZDACS-enabled engines will almost
// certainly need to include this, as it includes declarations for functions
// that acc declares implicitly.
#include <ACS_ZDoom.h>
#include <limits.h>
#include <stddef.h>
#include <stdfix.h>
#include <stdio.h>
// This declaration makes the DoAction function visible before its definition.
// It can also be used in other source files (usually by including a header
// file) to access functions and objects in other files.
void DoAction(void);
// This forward declares an address space.
__addrdef extern __map_arr map_var;
// And this forward declares an object in that address space.
extern int map_var MapInt;
// This declares and defines a map array address space. The name map_var is
// used as a type qualifier and all objects declared with a type qualified with
// it will be stored in the same underlying map array.
__addrdef __map_arr map_var;
// Declares and defines an int object in the map_var address space.
int map_var MapInt;
// Similarly, but for an array.
unsigned int map_var MapIntArr[16];
// If no address space is specified, objects declared at file-scope use the
// generic address space, which is implemented as a global array.
int IntVar;
// The typedef declaration can be used to give a type a new name, either for
// abstraction or convenience of typing. The declared name is identical to the
// underlying type, and either can be substituted for the other.
typedef int map_var map_int;
// This forward declaration of MapInt is equivalent to and compatible with the
// previous. Also worth noting that forward declarations can appear after the
// definition without error.
extern map_int MapInt;
// [[call("ScriptS")]] makes this function a named script.
// [[script("Open")]] gives it the OPEN type, making it an entry-point.
// By default, the name used will be the "mangled" name of the function. If the
// script needs to be referred to from outside GDCC, then [[extern("ACS")]]
// will make the mangled name the same as the declared name. Alternatively,
// [[address("Name Goes Here")]] will explicitly specify a name.
[[call("ScriptS"), script("Open")]]
void MainFunc(void)
{
while(1)
{
DoAction();
// ACS function names are prefixed to avoid name conflicts.
ACS_Delay(ACS_Random(35, 70));
}
}
// [[call("ScriptI")]] makes this function a numbered script. Its number will
// be automatically allocated. If a specific number is desired, then
// [[address(42)]] can be used with 42 replaced by the desired number.
// Automatically allocated numbers will avoid such explicit allocations.
[[call("ScriptI")]]
int CalcValue(void)
{
// This declares a local pointer object. The pointer itself is stored as a
// local variable, but the unsigned int objects that it accesses are stored
// as map_var. Pointer declarators are best read right-to-left.
unsigned int map_var *mapIntPtr;
// Store the address of an element of MapIntArr in mapIntPtr.
mapIntPtr = &MapIntArr[ACS_Timer() & 15];
// Do stuff with the referenced element.
*mapIntPtr += ACS_Timer() * *mapIntPtr;
// Being functions, scripts return values and are terminated using the
// return statement.
return *mapIntPtr & INT_MAX;
}
void DoAction(void)
{
// Being functions, scripts can be called like functions.
int val = CalcValue();
// An ACS string variable.
__str msg = NULL;
if(val == 42)
{
// ACS string literals have an s prefixed to them. Otherwise, it is a C
// string, which is addressed differently.
msg = s"Enjoying yourself?";
}
if(msg)
{
// This is used to initialize the native print buffer for a single print.
ACS_BeginPrint();
// __nprintf performs formatting the same as printf, but the output is
// sent to the native print buffer. The format string must be a C string.
// %S is used to print ACS strings.
__nprintf("George says, \"%S\"", msg);
// This prints the native print buffer to the screen as in ACS's Print.
ACS_EndPrint();
}
else
{
// This is equivalent to a Log call in ACS. Note the trailing linefeed.
// The buffer used by printf is only written when a linefeed is used.
printf("Nothing to say, move along.\n");
}
}
// This function demonstrates basic usage of floating and fixed point types.
void FloatVsFixed(void)
{
// GDCC supports single and double precision floating point.
float f;
double lf;
// The name accum is the canonical name for fixed-point (from Embedded C,
// short for accumulator), however stdfix.h also defines fixed.
accum k;
fixed x;
// The long accum type is an extended type with 1 sign bit, 31 integer bits,
// and 32 fractional bits. It can be used for calculations needing some
// extra intermediary precision.
long accum lk;
// Unsuffixed floating-point literals have type double. To give them accum
// type, use the k suffix.
f = 8.125f;
lf = 8.125;
k = 8.125k;
x = 8.125k;
lk = 8.125lk;
// Conversions between types is automatic, following normal C promotion
// rules.
lf = f * lf * k * x * lk;
lk = lf;
// Casts can also be explicit.
k = (accum)lf;
// Or using casts to improve intermediary precision. Note that type
// promotion causes both operations to be done as type double.
k = (double)k * x / 10;
}
// EOF