Ca3DE Map Scripting - a progress report

A forum about everything related to the Cafu World Editor CaWE: mapping, editing, scripting, making GUIs and fonts, using the BSP, PVS and Light compilers.
Post Reply
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:
Ca3DE Map Scripting - a progress report

Post by Carsten » 2007-08-24, 15:25

Hi all,

I'm happy and proud to announce that the following fragment of a Ca3DE map script is a real and fully working example of the latest Ca3DE scripting support! :wohow:

The MyLight:OnTrigger() function is called from a 3D world GUI in the map and performs one of the preset logic variants (variant=3 in the example below).

The main focus in this example script is on the coroutine.yield() function, which serves as the equivalent of both a wait(t) (wait t seconds until the script is resumed) as well as a waitFrame() (wait until end-of-frame) function as known e.g. from Doom 3 and Quake 4.
The other highlight in the code is the thread() function, which registers any Lua function for execution as a separate thread!

Code: Select all

function LightBlinkThread(lightEntity)
    -- Notice the great generality of this function:
    -- It can be used with *any* light entity, which is passed in via the lightEntity parameter!
    while (true) do
        lightEntity:SetColor(0, 255, 0);
        coroutine.yield(0.5);             -- Wait 0.5 seconds.
        if (not lightEntity.IsBlinking) then break; end

        lightEntity:SetColor(255, 0, 0);
        coroutine.yield(0.5);             -- Wait 0.5 seconds.
        if (not lightEntity.IsBlinking) then break; end
    end
end


MyLight.IsRed=false;
MyLight.IsBlinking=false;


function MyLight:OnTrigger()
    -- Choose the variant of logic you want to test.
    local variant=3;

    -- The logic is here and not in the GUI script because the GUI script code is also run on client prediction.
    -- This map script code is only run on server thinking.
    if (variant==1) then
        -- Implements a toggle switch.
        if (self.IsRed) then
            self:SetColor(0, 255, 0);
        else
            self:SetColor(255, 0, 0);
        end

        self.IsRed=not self.IsRed;
    elseif (variant==2) then
        -- Toggles between permanent red/green blinking and not blinking.
        if (self.IsBlinking) then
            -- Currently blinking, turn it off now.
            -- This will break the infinite loop below.
            self.IsBlinking=false;
            self:SetColor(oldR, oldG, oldB);
        else
            -- Currently not blinking, turn it on now.
            oldR, oldG, oldB=self:GetColor();
            self.IsBlinking=true;
            while (true) do
                self:SetColor(0, 255, 0);
                coroutine.yield(0.5);             -- Wait 0.5 seconds.
                if (not self.IsBlinking) then break; end

                self:SetColor(255, 0, 0);
                coroutine.yield(0.5);             -- Wait 0.5 seconds.
                if (not self.IsBlinking) then break; end
            end
        end
    elseif (variant==3) then
        -- As variant 2 above (toggles between permanent red/green blinking and not blinking),
        -- but implemented with an explicit thread (coroutine).
        -- This is the Ca3DE equivalent/analog to the Doom3 thread example in base\script\map_marscity2.script,
        -- but more elaborate and versatile (the LightBlinkThread function is reusable with any light entity).
        if (self.IsBlinking) then
            -- Currently blinking, turn it off now.
            -- This will break the infinite loop in the thread.
            self.IsBlinking=false;
            self:SetColor(oldR, oldG, oldB);
        else
            -- Currently not blinking, turn it on now.
            oldR, oldG, oldB=self:GetColor();
            self.IsBlinking=true;

            -- Register the function LightBlinkThread as a new thread. Call with "self" as the first parameter.
            thread(LightBlinkThread, self);
        end
    else
        -- Implements a one-time blink.
        local r, g, b=self:GetColor();  -- Save the previous color.

        self:SetColor(255, 255, 0);     -- Set to yellow.
        coroutine.yield(1);             -- Wait 1 sec.
        self:SetColor(r, g, b);         -- Set back previous color.
    end
end
The next release of Ca3DE will come with the above presented features -- stay tuned! :up:
Best regards,
Carsten
Denny
Posts:8
Joined:2007-08-14, 19:35
Location:Swe

Post by Denny » 2007-08-24, 20:36

So for non-programmers this means in short? :)
User avatar
Thrawn
Posts:302
Joined:2004-08-30, 10:38
Location:NRW, Germany
Contact:

Post by Thrawn » 2007-08-25, 10:05

That you can do whatever you can imagine concerning coding without having to learn C++ or other real programming languages.

Instead, you can create script files with text editors and the "programming" language LUA to do stuff. LUA is easier to learn than C++ so you can do a lot of things easier and quite a lot quicker!

@ Carsten:

Do I get it right that this LUA script is some sort of predefined light that can be called just by a line of script from another script, like: the map script?
Image
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Post by Carsten » 2007-08-26, 11:05

Thrawn wrote:Instead, you can create script files with text editors and the "programming" language LUA to do stuff. LUA is easier to learn than C++ so you can do a lot of things easier and quite a lot quicker!
... Exactly! :cheesy:
And each entity will come with a set of predefined functions that make programming it easy. For example, light entities have functions ("methods" in C++ lingo) like GetColor(), SetColor(), GetRadius(), SetRadius() etc.
Because each entity will also have a unique name in the future (e.g. the "MyLight" entity above), you can "program" the entities in your map in a very convenient manner.
@ Carsten:

Do I get it right that this LUA script is some sort of predefined light that can be called just by a line of script from another script, like: the map script?
Yes, that's essentially right.

I should have mentioned right in my first posting above that I will of course provide additional documentation later, complete with examples from introductory to advanced. :book:

Essentially, each entity in a map will (or should) have a unique name. In the above example, I had a light entity of type "PointLightSource" with name "MyLight" somewhere in the test map.
Another entity I had in that map has name "MyLift", of type "mover" and made of a single platform brush.

The C++ game code will provide all sorts of methods for each entity, depending on its type. As written above, there are methods like GetColor(), SetColor(), ... for light entities. For movers, there will be methods like Move(), Rotate(), etc.
You call such methods for example like

Code: Select all

MyLight:SetColor(255, 0, 0);         -- Set the light color of "MyLight" to red.
MyLift:Move(direction, duration);    -- Move "MyLift" into "direction" over "duration" seconds.
SoldierBarney:Attack(otherEntity);   -- ... you get the pattern.  ;)
HeavySubwayDoor:Open();
InvisibleWall:Hide();
Moreover, there are additional methods that you can write (provide) yourself, as for example the MyLight:OnTrigger() method above.
Whenever the game code tries to trigger an entity (e.g. because the player walked into a trigger volume), it will look for the OnTrigger() method of the targeted entity, and if found, run it.

The above MyLight:OnTrigger() is quite such an example: If we had a trigger volume whose target was the "MyLight" entity, then whenever something walked into the trigger volume, the OnTrigger() method of the target entity (here "MyLight") would be called.
An alternative (as implemented in my current test map) is to simply call "MyLight:OnTrigger()" straight from a 3D world GUI script. In this case, there is no requirement to name the method "OnTrigger()", it could have been named anything else as well, e.g. MyLight:ToggleLightOnAndOff().

Once a function is called, you can from there of course call any other function that you desired, both those that the C++ game code predefined, those that you provided for yourself, those from the Lua standard libraries, etc.


As soon as the scripting system is reasonably powerful, I'll also augment the existing maps with examples of its use (especially the TechDemo map, but also (some of) the smaller ones), as well as provide related documentation. So when the next version is being released, things should become a lot clearer. :up:
Best regards,
Carsten
Denny
Posts:8
Joined:2007-08-14, 19:35
Location:Swe

Post by Denny » 2007-08-26, 16:48

I'm just guessing along here. Let's say I want to make a light entity with the Lua-script. Would it be possible to use such Lua entities with the editor? :o

And uh sorry for not making any new content so far, my computer is sent for repair. (or rather get my RAM back to it's proper speed..... (500mhz compared to possible 1066mhz isn't good) :wink:
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Post by Carsten » 2007-08-26, 19:55

Hi Denny,

entities are made (placed, set, modified, etc.) in the editor, and the introduction of the script system will not change that.
In fact, one of the nice features of the script system is that it is complementary to the usual entity handling, i.e. it is an additional feature, not a replacement for something. Don't worry, I'm pretty sure that things will turn out pretty well for everyone. :wink:
Best regards,
Carsten
Post Reply

Who is online

Users browsing this forum: No registered users and 20 guests