TTLG|Thief|Bioshock|System Shock|Deus Ex|Mobile
Page 2 of 2 FirstFirst 12
Results 26 to 40 of 40

Thread: Understanding Squirrel Scripts

  1. #26
    Member
    Registered: Mar 2001
    Location: Ireland
    Post the code that you're trying to use.

  2. #27
    Member
    Registered: Jan 2012
    Location: Gèrmany
    What I want is to get a string config variable (ConfigGetRaw)
    But neither

    Code:
    str=string()
    Engine.ConfigGetRaw("resname_base",str)
    print(str)
    #Result empty
    Nor
    Code:
    str=string()
    Version.GetGame(str)
    print(str)
    #Result empty
    Seam to do anything with their str parameter. The return result is 1 (for success).


    EDIT: So either I'm doing something terribly wrong or something with string() is really terribly wrong. (or the functions)

    ---------------------
    Some knowledge i (think) figured out:

    string is a class here so string("init") is a class instance
    "init" get somewhere stored in it. I can not iterate it find out where or what's the index name.
    when used for example with print(string("init")) it invokes some kinda tostring() function. (also hidden)

    Any idea how the get the variables in a class.instance?

    ---
    string and int_ref got in their class body
    a constructor func
    two empty tables __setTable and __getTable
    as well as these two functions
    __overload_constructor0 and __overload_constructor1
    Last edited by Daraan; 6th Dec 2017 at 19:53.

  3. #28
    Member
    Registered: Nov 2001
    Location: uk
    I was just half way through writing something that contains most of that.
    printing anything invokes its tostring or _tostring function (depending on what it is and whether _tostring exists, that's used to override the built in tostring on something)

    I would do a foreach on it, but instances of the string class don't seem to let you do that. (I assume you equally already tried that)

    It doesn't to me look like you're doing anything wrong if that helps at all. The rather un-squirrel like syntax of all those functions in the name of making it the same as the c++ version it's a wrapper for.

  4. #29
    Member
    Registered: Nov 2001
    Location: uk
    Having poked at some stuff not in thief, you can't find out what's in a class instance unless the class implements methods for doing that (and that's normal for squirrel rather than specific to that class which is what I wanted to find out).

    if the class has a _nexti function in it then you should be able to foreach over the instance I think, you'd not generally do that unless the class was the sort of thing that you'd want to foreach over rather than just doing it because you want to treat it like a table and see what's in it because someone else wrote it and didn't tell you how it works.

    So I'm sticking with my unhelpful answer of that I agree the documentation says you should do what you're doing, it seems consistent with the rest of the script interface documentation and as far as I can see that ought to do what you'd expect.

  5. #30
    Member
    Registered: Jan 2012
    Location: Gèrmany
    Definitely a big thank you for looking into it as well.

    I want to break it down to the two main possibilities I see at the moment:
    Either the function results and 'return' of string are not in sync like
    script("init")->script.slot1
    Function(script)->script.slot2
    _tostring()->return script.slot1
    We could work around that if we knew the name of slot2

    But what I fear has the higher possibility.
    OR All the string & functions do not invoke their return part. (Maybe some typo deep inside the same function)
    Why I think that? All string & functions don't care/throw when you give them a totally wrong data type as parameters, the others specifically want a int/float_ref, vector.

  6. #31
    Member
    Registered: Sep 1999
    Location: Portland, OR
    Scripts are my weak suite because I haven't played with them at all, not even the basic ones. I've been playing in Dromed in every other aspect. I just want to thank everyone who is carving out this new opportunity in scripting. Thank you so much.

  7. #32
    ZylonBane
    Registered: Sep 2000
    Location: ZylonBane
    Here's a proof of concept script for a flashlight. I say proof of concept because, while it works, it updates at far too choppy a rate to be tolerable for actual gameplay. But if this script or something like it was implemented in native code it would probably be fine.



    It works pretty much the same as the flashlights in the original Deus Ex and Half-Life... just a dynamic light source shot out from the player view. So, not perfect, but about par for the course for engines of this vintage. Here's the script code:
    Code:
    function OnTimer() {
    	if (message().name == "flashlight") {
    		// some constants
    		local maxDist = 60;
    		local maxRadius = 15;
    		local maxLight = 200;
    		local deg2rad = PI / 180;
    		local lightObj = IsDataSet("lightObj") ? GetData("lightObj") : SetData("lightObj", Object.Named("lightsource"));
    		// get camera position/facing
    		local pos = Camera.GetPosition();
    		local face = Camera.GetFacing();
    		local faceY = face.y * deg2rad;
    		local faceZ = face.z * deg2rad;
    		// find out if there's a surface within range
    		local testPos = vector();
    		testPos.x = pos.x + maxDist * cos(faceY) * cos(faceZ);
    		testPos.y = pos.y + maxDist * cos(faceY) * sin(faceZ);
    		testPos.z = pos.z + maxDist * sin(faceY - PI);
    		local hitPos = vector();
    		// do the thing
    		if (Engine.PortalRaycast(pos, testPos, hitPos)) {
    			// calc distance to impact
    			local v = (hitPos - pos);
    			local d = sqrt(v.Dot(v));
    			local lightRad = maxRadius * (d / maxDist);
    			// step back from impact by radius of the light
    			local d2 = d - lightRad / 2;
    			if (d2 < 0) {
    				d2 = 0;
    			}
    			// calc actual light position
    			// (there's probably a better way to do this)
    			local lightPos = vector();
    			lightPos.x = pos.x + d2 * cos(faceY) * cos(faceZ);
    			lightPos.y = pos.y + d2 * cos(faceY) * sin(faceZ);
    			lightPos.z = pos.z + d2 * sin(faceY - PI);
    			// apply updated light params
    			Property.SetSimple(lightObj, "SelfLit", maxLight);
    			Property.SetSimple(lightObj, "SelfLitRad", lightRad);
    			Object.Teleport(lightObj, lightPos, face); // facing doesn't matter
    		}
    		else {
    			// disable light
    			Property.SetSimple(lightObj, "SelfLit", 0);
    		}
    	}
    }
    Note that this script uses terrain raycasting instead of object raycasting for performan-- ok actually I couldn't figure out how to get the objraycast function to work. Still, doesn't look too bad.

    I understand that NV's NVGizmos mission also had a flashlight demo that may have been similar to this in approach. I've never looked at it, so maybe I'm just reinventing the wheel here.
    Last edited by ZylonBane; 6th Mar 2018 at 21:23.

  8. #33
    Member
    Registered: Jun 2015
    Location: Germany
    I am using the Flashlight from NV in my FM Five Nights at Dayport. I like this tool, but it's more for moderns FM. In my Lost Place Contest FM, I want to use a latern with the light effect from Amnesia, but this was a fail.

  9. #34
    Member
    Registered: Sep 1999
    Location: Portland, OR
    Looks real good ZB. What about the smoothness of a flare's light? Why is that so smooth as a dynamic light and not this? I wonder if there isn't a way to focus down the light a flare does. Aside from that, I was thinking of making a AI with deadlights, I wonder how this could work coming out of an AI.

  10. #35
    ZylonBane
    Registered: Sep 2000
    Location: ZylonBane
    Flares are omnidirectional point light sources. Flashlights, on the other hand, project a directional beam. So having the illuminated area fade smoooothly out at the edges would have been wrong.

  11. #36
    Member
    Registered: Mar 2001
    Location: Ireland
    What's the timer interval on that flashlight? You seem to have left that out of the code segment.

  12. #37
    ZylonBane
    Registered: Sep 2000
    Location: ZylonBane
    You got me. The original version of that script was just piggybacking on the radiation check timer that's already on the SS2 player object. So it was running about... 10 times per second I think.

    Here's an updated version that now does object raycasting, and runs ~30 times per second. Somewhat amazingly it does both without bogging down the engine. The objraycast service is freakishly accurate too-- seems to be per-polygon, which has to be an expensive operation. This version also implements distance attenuation of the light and creating its own light emitter object.



    Dark's vertex lighting is so dodgy on large, low-poly objects that I had to implement directly adding extra light to objects to ensure that they would light up at all, which about doubled the length and complexity of the function, yet it's still very prone to visual inconsistencies. Oh well, not like the Half Life or Deus Ex flashlights were much better.

    Code:
    function OnBeginScript() {
    	SetOneShotTimer("flashlight", 0.5);
    }
    
    function OnTimer() {
    	if (message().name == "flashlight") {
    		// some constants
    		local maxDist = 60;
    		local minRadius = 3;
    		local maxRadius = 17;
    		local maxLight = 250;
    		local deg2rad = PI / 180;
    		local lightObj = GetData("flob");
    		local lastObjLit = GetData("lastObjLit");
    		// ensure flashlight object exists and ID saved
    		if (!lightObj) {
    			if (!Object.Named("flob")) {
    				lightObj = Object.Create("Marker");
    				Object.SetName(lightObj, "flob")
    			}
    			else {
    				lightObj = Object.Named("flob");
    			}
    			SetData("flob", lightObj);
    			SetData("lastObjLit", 0);
    			lastObjLit = 0;
    		}
    		// get camera position/facing
    		local pos = Camera.GetPosition();
    		local face = Camera.GetFacing();
    		local faceY = face.y * deg2rad;
    		local faceZ = face.z * deg2rad;
    		// find out if there's a surface within range
    		local testPos = vector();
    		testPos.x = pos.x + maxDist * cos(faceY) * cos(faceZ);
    		testPos.y = pos.y + maxDist * cos(faceY) * sin(faceZ);
    		testPos.z = pos.z + maxDist * sin(faceY - PI);
    		local hitPos = vector();
    		local hitObj = object();
    		local hitObjID = 0;
    		// return values: 0 nothing, 1 terrain, 2 object, 3 mesh
    		local rayHit = Engine.ObjRaycast(pos, testPos, hitPos, hitObj, 0, 0, lightObj, 0);
    		if (rayHit) {
    			// calc distance to impact
    			local v = (hitPos - pos);
    			local d = sqrt(v.Dot(v));
    			local lightRad = (maxRadius - minRadius) * (d / maxDist) + minRadius;
    			local lightBright = maxLight * (1 - (d / maxDist));
    			// step back from impact by radius of the light
    			local d2 = d - lightRad / 2;
    			// never position light behind player
    			if (d2 < 0) {
    				d2 = 0;
    			}
    			// calc actual light position
    			// (there's probably a better way to do this)
    			local lightPos = vector();
    			lightPos.x = pos.x + d2 * cos(faceY) * cos(faceZ);
    			lightPos.y = pos.y + d2 * cos(faceY) * sin(faceZ);
    			lightPos.z = pos.z + d2 * sin(faceY - PI);
    			// apply updated light params
    			Property.SetSimple(lightObj, "SelfLit", lightBright);
    			Property.SetSimple(lightObj, "SelfLitRad", lightRad);
    			Object.Teleport(lightObj, lightPos, face); // facing doesn't matter
    			// handle object lighting
    			// (objects often need some help due to vertex lighting plus low poly counts)
    			if (rayHit == 2) {
    				hitObjID = hitObj.tointeger();
    				// check for object focus change
    				if (hitObjID != abs(lastObjLit)) {
    					killObjLight(lastObjLit);
    					// don't mess with objects that already have Extra Light
    					if (Property.Possessed(hitObjID, "ExtraLight")) {
    						lastObjLit = -hitObjID;
    					}
    					else {
    						lastObjLit = hitObjID;
    						Property.Set(hitObjID, "ExtraLight", "Additive?", TRUE);
    					}
    					SetData("lastObjLit", lastObjLit);
    				}
    				if (lastObjLit > 0) {
    					// fade to target brightness
    					local curLum = Property.Get(hitObjID, "ExtraLight", "Amount (-1..1)");
    					// (lightBright / maxLight) / 2) is the target extra light
    					Property.Set(hitObjID, "ExtraLight", "Amount (-1..1)", curLum + (((lightBright / maxLight) / 2) - curLum) / 3);
    				}
    			}
    			else {
    				killObjLight(lastObjLit);
    			}
    		}
    		else {
    			// light didn't reach anything
    			Property.SetSimple(lightObj, "SelfLit", 0);
    			killObjLight(lastObjLit);
    		}
    		// again!
    		SetOneShotTimer("flashlight", 0.0333);
    	}
    }
    
    // remove extra light from last lit object
    function killObjLight(lastObjLit) {
    	if (lastObjLit != 0) {
    		SetData("lastObjLit", 0);
    		if (lastObjLit > 0) {
    			Property.Remove(lastObjLit, "ExtraLight");
    		}
    	}
    }

  13. #38
    Zombified
    Registered: Sep 2004
    Quote Originally Posted by ZylonBane View Post
    directly adding extra light to objects
    nuts. also yeah, this is completely usable - as long as it's possible to make the AIs react to the light (investigate).

  14. #39
    ZylonBane
    Registered: Sep 2000
    Location: ZylonBane
    Why nuts?

  15. #40
    Zombified
    Registered: Sep 2004
    out of the box thinking/solution. also a bit of pun, because why not.

Page 2 of 2 FirstFirst 12

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •