Hard Light Productions Forums
Modding, Mission Design, and Coding => FS2 Open Coding - The Source Code Project (SCP) => Topic started by: Aardwolf on May 22, 2009, 09:00:39 am
-
The result of some work I did with the FS2 code to make possible some things I wanted for the RTS Mod, this patch exposes the following 3 functions to scripting:
1. boolean Ship.isWarpingIn()
True if the ship is warping in (i.e. blue on the radar)
2. int gr.drawModel(model, position, orientation)
Draws the model. Nonzero return values are errors, returns 0 if successful. Note, this function is basically just meant to simulate the function WMCoolmon came up with, but which doesn't seem to have been committed to trunk.
3. int,int,int,int gr.drawTargetingBrackets(Object object, [boolean draw=true, int padding=5])
Draws targeting brackets around a model (or optionally doesn't). Returns the left, top, right, and bottom edge coordinates.
I am also thinking about making a more generalized ship.flags and possibly ship class flags getter function, because I reckon there's a lot that could be done with that.
/me expresses an interest in working with the SCP
File contents of the .patch file:
Index: lua.cpp
===================================================================
--- lua.cpp (revision 5301)
+++ lua.cpp (working copy)
@@ -11,10 +11,12 @@
#include "graphics/font.h"
#include "globalincs/linklist.h"
#include "globalincs/pstypes.h"
+#include "hud/hudbrackets.h"
#include "iff_defs/iff_defs.h"
#include "io/key.h"
#include "io/mouse.h"
#include "io/timer.h"
+#include "jumpnode/jumpnode.h"
#include "lighting/lighting.h"
#include "mission/missioncampaign.h"
#include "mission/missiongoals.h"
@@ -6060,6 +6062,25 @@
return ADE_RETURN_TRUE;
}
+// Aardwolf's function for finding if a ship should be drawn as blue on the radar/minimap
+ADE_FUNC(isWarpingIn, l_Ship, NULL, "Checks if ship is warping in", "boolean", "True if the ship is warping in, false or nil otherwise")
+{
+ object_h *objh;
+ if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
+ return ADE_RETURN_NIL;
+
+ if(!objh->IsValid())
+ return ADE_RETURN_NIL;
+
+ ship *shipp = &Ships[objh->objp->instance];
+ if(shipp->flags & SF_ARRIVING_STAGE_1)
+ {
+ return ADE_RETURN_TRUE;
+ }
+
+ return ADE_RETURN_FALSE;
+}
+
//**********HANDLE: Weapon
ade_obj<object_h> l_Weapon("weapon", "Weapon handle", &l_Object);
@@ -8053,6 +8074,159 @@
return ADE_RETURN_TRUE;
}
+// Aardwolf's test code to render a model, supposed to emulate WMC's gr.drawModel function
+ADE_FUNC(drawModel, l_Graphics, "model, position, orientation", "Draws the given model with the specified position and orientation", "int", "Zero if successful, otherwise an integer error code")
+{
+ model_h *mdl = NULL;
+ vec3d *v = &vmd_zero_vector;
+ matrix_h *mh = NULL;
+ if(!ade_get_args(L, "ooo", l_Model.GetPtr(&mdl), l_Vector.GetPtr(&v), l_Matrix.GetPtr(&mh)))
+ return ade_set_args(L, "i", 1);
+
+ if(mdl == NULL)
+ return ade_set_args(L, "i", 2);
+
+ int model_num = mdl->GetID();
+ if(model_num < 0)
+ return ade_set_args(L, "i", 3);
+
+ //Handle angles
+ matrix *orient = mh->GetMatrix();
+
+ //Clip
+ gr_set_clip(0, 0, gr_screen.max_w, gr_screen.max_h, false);
+
+ //Handle 3D init stuff
+ g3_start_frame(1);
+
+ vec3d cam_pos;
+ matrix cam_orient;
+
+ camid cid = cam_get_current();
+ cid.getCamera()->get_info(&cam_pos, &cam_orient);
+
+ g3_set_view_matrix(&cam_pos, &cam_orient, View_zoom);
+
+ if (!Cmdline_nohtl) {
+ gr_set_proj_matrix( Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance);
+ gr_set_view_matrix(&Eye_position, &Eye_matrix);
+ }
+
+ //Draw the ship!!
+ model_clear_instance(model_num);
+ model_set_detail_level(0);
+ model_render(model_num, orient, v, MR_NORMAL);
+
+ //OK we're done
+ if (!Cmdline_nohtl)
+ {
+ gr_end_view_matrix();
+ gr_end_proj_matrix();
+ }
+
+ //Bye!!
+ g3_end_frame();
+ gr_reset_clip();
+
+ return ade_set_args(L, "i", 0);
+}
+
+// Aardwolf's targeting brackets function
+ADE_FUNC(drawTargetingBrackets, l_Graphics, "object Object, [boolean draw=true, int padding=5]",
+ "Gets the edge positions of targeting brackets for the specified object. The brackets will only be drawn if draw is true or the default value of draw is used. Brackets are drawn with the current color. The brackets will have a padding (distance from the actual bounding box); the default value (used elsewhere in FS2) is 5.",
+ "number,number,number,number",
+ "Left, top, right, and bottom positions of the brackets, or nil if invalid")
+{
+ if(!Gr_inited) {
+ return ADE_RETURN_NIL;
+ }
+
+ object_h *objh = NULL;
+ bool draw_box = true;
+ int padding = 5;
+
+ if( !ade_get_args(L, "o|bi", l_Object.GetPtr(&objh), &draw_box, &padding) ) {
+ return ADE_RETURN_NIL;
+ }
+
+ // The following code is mostly copied from
+ // void hud_show_brackets(object *targetp, vertex *projected_v)
+ // in hudtarget.cpp
+
+ if( !objh->IsValid()) {
+ return ADE_RETURN_NIL;
+ }
+
+ object *targetp = objh->objp;
+
+ int x1,x2,y1,y2;
+ int bound_rc;
+
+ int modelnum;
+
+ switch ( targetp->type ) {
+ case OBJ_SHIP:
+ modelnum = Ship_info[Ships[targetp->instance].ship_info_index].model_num;
+ bound_rc = model_find_2d_bound_min( modelnum, &targetp->orient, &targetp->pos,&x1,&y1,&x2,&y2 );
+ if ( bound_rc != 0 ) {
+ return ADE_RETURN_NIL;
+ }
+ break;
+
+ case OBJ_DEBRIS:
+ modelnum = Debris[targetp->instance].model_num;
+ bound_rc = submodel_find_2d_bound_min( modelnum, Debris[targetp->instance].submodel_num, &targetp->orient, &targetp->pos,&x1,&y1,&x2,&y2 );
+ if ( bound_rc != 0 ) {
+ return ADE_RETURN_NIL;
+ }
+ break;
+
+ case OBJ_WEAPON:
+ Assert(Weapon_info[Weapons[targetp->instance].weapon_info_index].subtype == WP_MISSILE);
+ modelnum = Weapon_info[Weapons[targetp->instance].weapon_info_index].model_num;
+ bound_rc = model_find_2d_bound_min( modelnum, &targetp->orient, &targetp->pos,&x1,&y1,&x2,&y2 );
+ break;
+
+ case OBJ_ASTEROID:
+ {
+ int pof = 0;
+ pof = Asteroids[targetp->instance].asteroid_subtype;
+ modelnum = Asteroid_info[Asteroids[targetp->instance].asteroid_type].model_num[pof];
+ bound_rc = model_find_2d_bound_min( modelnum, &targetp->orient, &targetp->pos,&x1,&y1,&x2,&y2 );
+ }
+ break;
+
+ case OBJ_JUMP_NODE:
+ modelnum = targetp->jnp->get_modelnum();
+ bound_rc = model_find_2d_bound_min( modelnum, &targetp->orient, &targetp->pos,&x1,&y1,&x2,&y2 );
+ break;
+
+ default:
+ // should never happen
+ Int3();
+ return ADE_RETURN_NIL;
+ }
+
+ x1 -= padding;
+ x2 += padding;
+ y1 -= padding;
+ y2 += padding;
+ if ( draw_box ) {
+ if( !(g3_in_frame() > 0) )
+ {
+ g3_start_frame(0);
+ draw_brackets_square(x1, y1, x2, y2, false);
+ g3_end_frame();
+ }
+ else
+ {
+ draw_brackets_square(x1, y1, x2, y2, false);
+ }
+ }
+
+ return ade_set_args(L, "iiii", x1, y1, x2, y2);
+}
+
#define MAX_TEXT_LINES 256
static char *BooleanValues[] = {"False", "True"};
static const int NextDrawStringPosInitial[] = {0, 0};
-
Nice. Very nice. :yes:
With flags there is the problem that game uses (mostly) single bits as flags. This means you either need to include code the 'decypher' the one or two ints containing the flags before handing the processed lot over to script or then try to provide good enough documentation so that it would be enough to use just the int.
-
heres a couple lua funcs i added
ADE_FUNC(isAfterburnerActive, l_Physics, NULL, "True if Afterburners are on, false or nil if not", "boolean", "Detects whether afterburner is active")
{
physics_info_h *pih;
if(!ade_get_args(L, "o", l_Physics.GetPtr(&pih)))
return ADE_RETURN_NIL;
if(!pih->IsValid())
return ade_set_error(L, "b", false);
if (pih->pi->flags & PF_AFTERBURNER_ON)
return ade_set_args(L, "b", true);
else
return ade_set_args(L, "b", false);
}
if you ned to see if the afterburner is on or not, just call the function and it will return a bool
ADE_FUNC(renderTechModel2, l_Shipclass, "X1, Y1, X2, Y2, orientation Orientation=null, [Zoom multiplier]", "Draws ship model as if in techroom", "boolean", "Whether ship was rendered")
{
int x1,y1,x2,y2;
int idx;
float zoom = 1.3f;
matrix_h *mh = NULL;
if(!ade_get_args(L, "oiiiio|f", l_Shipclass.Get(&idx), &x1, &y1, &x2, &y2, l_Matrix.GetPtr(&mh), &zoom))
return ade_set_error(L, "b", false);
if(idx < 0 || idx > Num_ship_classes)
return ade_set_args(L, "b", false);
if(x2 < x1 || y2 < y1)
return ade_set_args(L, "b", false);
ship_info *sip = &Ship_info[idx];
//Make sure model is loaded
sip->model_num = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0], 0);
if(sip->model_num < 0)
return ade_set_args(L, "b", false);
//Handle angles
matrix *orient = mh->GetMatrix();
//Clip
gr_set_clip(x1,y1,x2-x1,y2-y1,false);
//Handle 3D init stuff
g3_start_frame(1);
g3_set_view_matrix(&sip->closeup_pos, &vmd_identity_matrix, sip->closeup_zoom * zoom);
if (!Cmdline_nohtl) {
gr_set_proj_matrix( Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance);
gr_set_view_matrix(&Eye_position, &Eye_matrix);
}
//Handle light
light_reset();
vec3d light_dir = vmd_zero_vector;
light_dir.xyz.y = 1.0f;
light_add_directional(&light_dir, 0.65f, 1.0f, 1.0f, 1.0f);
light_rotate_all();
//Draw the ship!!
model_clear_instance(sip->model_num);
model_set_detail_level(0);
model_render(sip->model_num, orient, &vmd_zero_vector, MR_LOCK_DETAIL | MR_AUTOCENTER | MR_NO_FOGGING);
//OK we're done
if (!Cmdline_nohtl)
{
gr_end_view_matrix();
gr_end_proj_matrix();
}
//Bye!!
g3_end_frame();
gr_reset_clip();
return ade_set_args(L, "b", true);
}
this varient of render tech model excepts a matrix rather than an odball set of percentages
-
gr.drawModel
YES! Put this back in the official builds please! :D
-
Well I was talking to Nuke trying to make sense of why he wanted his own render model function, and I eventually got what he was saying. My function uses world-space coordinates, whereas his is camera-space, and suited better for drawing stuff like the techroom ships or the target view ship render.
gr.drawModel
YES! Put this back in the official builds please! :D
Unfortunately I'm not in charge of that (I'm not an SCP team-member ... yet). But yeah, I was almost certain it already had been implemented, and kind of disappointed to not be able to find it. So I made one of my own, which basically worked the same way as WMC's (at least for the user, as far as the code for it I can't say it works the same way internally).
-
Unfortunately I'm not in charge of that (I'm not an SCP team-member ... yet).
So apply to join us. :)
-
What sort of application are we talking about? :drevil:
A further addition to lua.cpp:
// Aardwolf's modified forceMousePosition function, because the other one doesn't work some reason
ADE_FUNC(setCursorPosition, l_Mouse, "x, y", "moves the cursor to the given coordinates\nshould also do everything forceMousePosition would do", "boolean", "true if it worked, false otherwise")
{
if(!mouse_inited)
return ADE_RETURN_FALSE;
if(!Gr_inited)
return ADE_RETURN_FALSE;
int x, y;
if (!(ade_get_args(L, "ii", &x, &y)))
return ADE_RETURN_FALSE;
if (!((x >= 0) && (x <= gr_screen.max_w)))
return ADE_RETURN_FALSE;
if (!((y >= 0) && (y <= gr_screen.max_h)))
return ADE_RETURN_FALSE;
mouse_set_pos(x, y);
return ADE_RETURN_TRUE;
}
Basically, the io.forceMousePosition function doesn't seem to be doing anything. It returns true, which it says means it's working, but there's no visible effect. Since I wasn't able to find anything about it by searching the forums, and Wanderer wasn't on IRC (I was under the impression he might know what it was supposed to do), I wrote my own.
I'm still testing this, though.
Edit: It appears to work as intended, but I'll need to change how I'm using it because it's not syncing right.
Edit, The Second: And for some stupid reason the "On Mouse Moved" hook is never being called. I'm looking into this now.
-
Well, the function (see above) works better than the existing one (which had no visible effects), but the goal I thought I could use it for seems unachievable.
The conditional hook $On Mouse Moved: doesn't execute (but if there are parse errors it complains about them), and I couldn't figure out why.
Also, my attempt to get around this problem by putting the code I had there in its own function and calling it a) in the global $Simulation: hook and b) in the conditional $On HUD Draw: hooks didn't work out, because the cursor wouldn't stay still.
While I could in theory achieve what I'm aiming for by manually drawing the cursor, I'm not sure I want to do that. Since this is turning into mod-specific comments, I'm not going to spend too much more effort describing it, at least not in this thread. I would however, like to summarize with the following list of observations:
- The On Mouse Moved never runs (or at least doesn't seem to.
- The io.forceMousePosition function doesn't seem to do anything.
- The function I wrote at least does what the aforementioned function seems like it is meant to do, although I can't guarantee my implementation is flawless either.
-
io.forceMousePosition works fine in my mouse script when running the script (slightly modified) in trunk build.
-
on something unrelated i might want to be able to iterate through all game objects rather than just ships or weapons for things like physics scripts. working on the atmospherics and orbital mechanics script leads me to believe that its a real pain in the ass to iterate through each kind of object in the game, when you're essentially doing the same thing to every object in the game the result is 4 loops that do the same thing. what i need is mn.Objects[].
the other thing i might do is add a function to get any objects obj_num. its good if you need to uniquely identify any object in the game without the luxury of a unique name. i had to code one for weapons because theres no way to tag custom meta info to an instance of a weapon. in doing so i found that it would be really awesome if every type of object had this function. adding this shoud just be a simple cut and paste job, but id like to add it at the object level.
since im doing so much to rape the less than realistic physics that freespace uses, mutilating their carcass and replacing it with an ultra realistic piece of scripting genious. it would be kind of awesome if i can disable them all together. it may also be necessary to be able to call collision detection functions, possibly modified to work without upper limits on how fast things can go.
opinions?
-
Might as well start applying these changes...
These all seem perfectly reasonable
boolean Ship.isWarpingIn()
int gr.drawModel(model, position, orientation)
int,int,int,int gr.drawTargetingBrackets(Object object, [boolean draw=true, int padding=5])
isAfterburnerActive
Is the alternate tech model render necessary as there already is a tech model render function?
Also i changed the forceMousePosition to use mouse_set_pos instead of mouse_force_pos as it appears that there are differences between debug and release builds on how mouse is handled.
-
Might as well start applying these changes...
These all seem perfectly reasonable
boolean Ship.isWarpingIn()
int gr.drawModel(model, position, orientation)
int,int,int,int gr.drawTargetingBrackets(Object object, [boolean draw=true, int padding=5])
isAfterburnerActive
Is the alternate tech model render necessary as there already is a tech model render function?
Also i changed the forceMousePosition to use mouse_set_pos instead of mouse_force_pos as it appears that there are differences between debug and release builds on how mouse is handled.
rendertechmodel2 uses a matrix instead of %rotation. i created it mainly so i could do a semi-3d attitude indicator which required some matrix magic in order to look right. i was looking at the possibility of overloading the existing function to take either a matrix, eulers, or the default percentages. but that doesnt seem likely without completely changing the parameters around as far as i can tell. my version really only changes a few lines of code. on the other hand its something that i can think of 50 other uses for and it really simplifies things in the long run.
-
OK then.. valid enough reasoning.. I'll try to commit all these when i have time - possibly today
-
Yay... Question: will my modified versions realize that the commit is a commit of my stuff, or will I have to do some messing around to get that working right?
-
I noticed just now that this crashes. I've figured out what's wrong and made a patch:
targetingbrackets_crash_fix.patch
Index: lua.cpp
===================================================================
--- lua.cpp (revision 5392)
+++ lua.cpp (working copy)
@@ -8447,11 +8447,20 @@
int bound_rc, pof;
int modelnum;
+ bool not_in_frame = !(g3_in_frame() > 0);
+
+ if( not_in_frame ) {
+ g3_start_frame(0);
+ }
+
switch ( targetp->type ) {
case OBJ_SHIP:
modelnum = Ship_info[Ships[targetp->instance].ship_info_index].model_num;
bound_rc = model_find_2d_bound_min( modelnum, &targetp->orient, &targetp->pos,&x1,&y1,&x2,&y2 );
if ( bound_rc != 0 ) {
+ if( not_in_frame ) {
+ g3_end_frame();
+ }
return ADE_RETURN_NIL;
}
break;
@@ -8459,6 +8468,9 @@
modelnum = Debris[targetp->instance].model_num;
bound_rc = submodel_find_2d_bound_min( modelnum, Debris[targetp->instance].submodel_num, &targetp->orient, &targetp->pos,&x1,&y1,&x2,&y2 );
if ( bound_rc != 0 ) {
+ if( not_in_frame ) {
+ g3_end_frame();
+ }
return ADE_RETURN_NIL;
}
break;
@@ -8487,15 +8499,11 @@
y1 -= padding;
y2 += padding;
if ( draw_box ) {
- if( !(g3_in_frame() > 0) ) {
- g3_start_frame(0);
- draw_brackets_square(x1, y1, x2, y2, false);
- g3_end_frame();
- }
- else {
- draw_brackets_square(x1, y1, x2, y2, false);
- }
+ draw_brackets_square(x1, y1, x2, y2, false);
}
+ if( not_in_frame ) {
+ g3_end_frame();
+ }
return ade_set_args(L, "iiii", x1, y1, x2, y2);
}
I'm also uploading it as an attachment so it's easier to download. The above version is basically just so if the attachment dies, it's still here.
[attachment deleted by MSC
-
Mantised, as per a suggestion by blowfish.
Edit: link: http://scp.indiegames.us/mantis/view.php?id=1949
Edit II: and for some stupid reason Mantis assigned it to WMCoolmon automagically, even though he's AWOL for an indeterminate duration...
-
Mantised, as per a suggestion by blowfish.
Edit: link: http://scp.indiegames.us/mantis/view.php?id=1949
Edit II: and for some stupid reason Mantis assigned it to WMCoolmon automagically, even though he's AWOL for an indeterminate duration...
Patch committed, and unmantised from WMC
-
Ah good
-
heres a new one i just did
ADE_FUNC(getSignature, l_Object, NULL, "Gets the object's unique signature", "number", "Returns the objects unique numeric signature, useful for creating a metadata sytem")
{
object_h *oh;
if(!ade_get_args(L, "o", l_Object.GetPtr(&oh)))
return ade_set_error(L, "i", 0);
if(!oh->IsValid())
return ade_set_error(L, "i", 0);
return ade_set_args(L, "i", oh->objp->signature);
}
it gets an object's unique signature (regaurdless of its breed). you can use this to make a global metadata system that is object type independent.
-
Does that work? I mean, if an object becomes invalid, will it avoid using the same value for any new objects?
-
its just a unique identifier, like the names the rts uses. you need to come up with a means to tell if the object is still useful. isValid does that fine. periodically loop through the objects if they are valid but arent in the metasystem, add them, if they are in the metasystem but not valid, clear them. luais a memory whore so its absolutely neccisary to clear dead meta entries from the system.
-
heres a couple of "why the **** weren't they in lua to begin with" function i wrote for ship
ADE_VIRTVAR(WeaponEnergy, l_Ship, "number", "Current weapon energy reserves", "number", "Ship current weapon energy reserve level, or -1 if invalid")
{
object_h *objh;
float neweng = -1;
if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &neweng))
return ade_set_error(L, "f", -1.0f);
if(!objh->IsValid())
return ade_set_error(L, "f", -1.0f);
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR && neweng > -1)
shipp->weapon_energy = neweng;
return ade_set_args(L, "f", shipp->weapon_energy);
}
ADE_VIRTVAR(WeaponEnergyMax, l_Ship, "number", "Maximum weapon energy", "number", "Ship maximum weapon energy reserve level, or -1 if invalid")
{
object_h *objh;
float neweng = -1;
if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &neweng))
return ade_set_error(L, "f", -1.0f);
if(!objh->IsValid())
return ade_set_error(L, "f", -1.0f);
ship_info *sip = &Ship_info[Ships[objh->objp->instance].ship_info_index];
if(ADE_SETTING_VAR && neweng > -1)
sip->max_weapon_reserve = neweng;
return ade_set_args(L, "f", sip->max_weapon_reserve);
}
ive tested them and they work fine
-
It'd still be nice to get a general-use sexp interpreter for Lua (or something similar)...
That is, being able to execute sexp-format code from Lua, just like we can execute Lua code from the sexp side.
-
that might actually make sexps useful :D
-
i fixed a bug with setFOV(), some of the type flags were set wrong in the ade_get_args call
ADE_FUNC(setFOV, l_Camera, "[number FOV, number Zoom Time, number Zoom Acceleration Time, number Zoom deceleration Time]",
"Sets camera FOV"
"<br>FOV is the final field of view, in radians, of the camera."
"<br>Zoom Time is the total time to take zooming in or out."
"<br>Acceleration Time is the total time it should take the camera to get up to full zoom speed."
"<br>Deceleration Time is the total time it should take the camera to slow down from full zoom speed.",
"boolean", "true if successful, false or nil otherwise")
{
camid cid;
float n_fov = VIEWER_ZOOM_DEFAULT;
float time=0.0f;
float acc_time=0.0f;
float dec_time=0.0f;
if(!ade_get_args(L, "o|ffff", l_Camera.Get(&cid), &n_fov, &time, &acc_time, &dec_time))
return ADE_RETURN_NIL;
if(!cid.isValid())
return ADE_RETURN_NIL;
cid.getCamera()->set_fov(n_fov, time, acc_time, dec_time);
return ADE_RETURN_TRUE;
}
-
Okay, here are some naive changes I made to several functions to make a few additional scripting functions work. I'm quite certain this could have been done in a prettier way, but I'm not experienced enough to see it....
[attachment deleted by Tolwyn]
-
You don't really need to leave commented out code in the files. The beauty of SVN is we can just revert back and the patch itself shows what was there before anyway.
-
<Jayne>Well, now I know that</Jayne>