Author Topic: [CODE REVIEW] Admiral MS' features for post-3.7.0  (Read 6819 times)

0 Members and 1 Guest are viewing this topic.

[CODE REVIEW] Admiral MS' features for post-3.7.0
Following zookeepers' example I'll reuse this topic and post a list of features for review. I'm planning to add a few more things.

Ship orders access for scripting including modification of some values of an order ( shiporder = ship.Orders, order = shiporders[1], order:getType(), order.Priority, order.Target, order.TargetSubsystem, order:remove() ). Is partially based in zookeepers' patch.
Code: [Select]
Index: code/parse/lua.cpp
===================================================================
--- code/parse/lua.cpp (revision 10284)
+++ code/parse/lua.cpp (working copy)
@@ -522,7 +522,7 @@
 //that any new enumerations have indexes of NEXT INDEX (see below)
 //or after. Don't forget to increment NEXT INDEX after you're done.
 //=====================================
-static const int ENUM_NEXT_INDEX = 69; // <<<<<<<<<<<<<<<<<<<<<<
+static const int ENUM_NEXT_INDEX = 71; // <<<<<<<<<<<<<<<<<<<<<<
 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 static flag_def_list Enumerations[] = {
  #define LE_ALPHABLEND_FILTER 14
@@ -603,6 +603,12 @@
  #define LE_ORDER_WAYPOINTS_ONCE 46
  { "ORDER_WAYPOINTS_ONCE", LE_ORDER_WAYPOINTS_ONCE, 0},
 
+ #define LE_ORDER_ATTACK_WING 69
+ { "ORDER_ATTACK_WING", LE_ORDER_ATTACK_WING, 0},
+
+ #define LE_ORDER_GUARD_WING 70
+ { "ORDER_GUARD_WING", LE_ORDER_GUARD_WING, 0},
+
  #define LE_PARTICLE_DEBUG 4
  { "PARTICLE_DEBUG", LE_PARTICLE_DEBUG, 0},
 
@@ -2434,133 +2440,6 @@
  return ade_set_args(L, "b", dbh->IsValid());
 }
 
-//**********HANDLE: order
-struct order_h
-{
- object_h objh;
- int odx;
- int sig;
-
- order_h() {
- objh = object_h();
- odx = -1;
- sig = -1;
- }
-
- order_h(object *objp, int n_odx)
- {
- objh = object_h(objp);
- if(objh.IsValid() && objh.objp->type == OBJ_SHIP && n_odx > -1 && n_odx < MAX_AI_GOALS)
- {
- odx = n_odx;
- sig = Ai_info[Ships[objh.objp->instance].ai_index].goals[odx].signature;
- }
- else
- {
- odx = -1;
- sig = -1;
- }
- }
-
- bool IsValid()
- {
- return (this != NULL && objh.IsValid() && objh.objp->type == OBJ_SHIP && odx > -1 && odx < MAX_AI_GOALS && sig == Ai_info[Ships[objh.objp->instance].ai_index].goals[odx].signature);
- }
-};
-
-ade_obj<order_h> l_Order("order", "order handle");
-
-ADE_FUNC(remove, l_Order, NULL, "Removes the given order from the ship's priority queue.", "boolean", "True if order was successfully removed, otherwise false or nil.")
-{
- order_h *ohp = NULL;
- if(!ade_get_args(L, "o", l_Order.GetPtr(&ohp)))
- return ADE_RETURN_NIL;
-
- if(!ohp->IsValid())
- return ADE_RETURN_FALSE;
-
- ai_info *aip = &Ai_info[Ships[ohp->objh.objp->instance].ai_index];
-
- ai_remove_ship_goal(aip, ohp->odx);
-
- return ADE_RETURN_TRUE;
-}
-
-//**********HANDLE: shiporders
-ade_obj<object_h> l_ShipOrders("shiporders", "Ship orders");
-
-ADE_FUNC(__len, l_ShipOrders, NULL, "Number of textures on ship", "number", "Number of textures on ship, or 0 if handle is invalid")
-{
- object_h *objh = NULL;
- if(!ade_get_args(L, "o", l_ShipOrders.GetPtr(&objh)))
- return ade_set_error(L, "i", 0);
-
- if(!objh->IsValid() || objh->objp->type != OBJ_SHIP || Ships[objh->objp->instance].ai_index < 0)
- return ade_set_error(L, "i", 0);
-
- return ade_set_args(L, "i", ai_goal_num(&Ai_info[Ships[objh->objp->instance].ai_index].goals[0]));
-}
-
-ADE_INDEXER(l_ShipOrders, "number Index/string TextureFilename", "Array of ship orders", "order", "Order, or invalid texture handle on failure")
-{
- object_h *objh = NULL;
- char *s = NULL;
- order_h *oh = NULL;
- int i;
-
- if (!ade_get_args(L, "os|o", l_ShipOrders.GetPtr(&objh), &s, l_Order.GetPtr(&oh)))
- return ade_set_error(L, "o", l_Order.Set(order_h()));
-
- if (!objh->IsValid() || s==NULL)
- return ade_set_error(L, "o", l_Order.Set(order_h()));
-
- ai_info *aip = &Ai_info[Ships[objh->objp->instance].ai_index];
-
- //Determine index
- int idx = atoi(s) - 1; //Lua->FS2
-
- if (idx < 0 || idx >= MAX_AI_GOALS)
- return ade_set_error(L, "o", l_Order.Set(order_h()));
-
- int num = 0;
- for(i = 0; i < MAX_AI_GOALS; i++)
- {
- if(aip->goals[i].ai_mode != AI_GOAL_NONE)
- {
- if(idx == num)
- break;
-
- num++;
- }
- }
-
- if(i >= MAX_AI_GOALS)
- return ade_set_error(L, "o", l_Order.Set(order_h()));
-
- if (ADE_SETTING_VAR)
- {
- if(!oh->IsValid())
- {
- ai_remove_ship_goal(aip, i);
- }
- else
- {
- aip->goals[i] = Ai_info[Ships[oh->objh.objp->instance].ai_index].goals[oh->odx];
- }
- }
-
- return ade_set_args(L, "o", l_Order.Set(order_h(objh->objp, i)));
-}
-
-ADE_FUNC(isValid, l_ShipOrders, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
-{
- object_h *oh;
- if(!ade_get_args(L, "o", l_ShipOrders.GetPtr(&oh)))
- return ADE_RETURN_NIL;
-
- return ade_set_args(L, "b", oh->IsValid());
-}
-
 //**********HANDLE: physics
 struct physics_info_h
 {
@@ -7596,7 +7475,411 @@
  return ade_set_args(L, "b", sso->IsValid());
 }
 
+//**********HANDLE: order
+struct order_h
+{
+ object_h objh;
+ int odx;
+ int sig;
+ ai_goal *aigp;
 
+ order_h() {
+ objh = object_h();
+ odx = -1;
+ sig = -1;
+ aigp = NULL;
+ }
+
+ order_h(object *objp, int n_odx)
+ {
+ objh = object_h(objp);
+ if(objh.IsValid() && objh.objp->type == OBJ_SHIP && n_odx > -1 && n_odx < MAX_AI_GOALS)
+ {
+ odx = n_odx;
+ sig = Ai_info[Ships[objh.objp->instance].ai_index].goals[odx].signature;
+ aigp = &Ai_info[Ships[objh.objp->instance].ai_index].goals[odx];
+ }
+ else
+ {
+ odx = -1;
+ sig = -1;
+ aigp = NULL;
+ }
+ }
+
+ bool IsValid()
+ {
+ if (objh.objp == NULL || aigp == NULL)
+ return false;
+
+ return (this != NULL && objh.IsValid() && objh.objp->type == OBJ_SHIP && odx > -1 && odx < MAX_AI_GOALS && sig == Ai_info[Ships[objh.objp->instance].ai_index].goals[odx].signature);
+ }
+};
+
+ade_obj<order_h> l_Order("order", "order handle");
+
+ADE_VIRTVAR(Priority, l_Order, "number", "Priority of the given order", "number", "Order priority or 0 if invalid")
+{
+ order_h *ohp = NULL;
+ int priority = 1;
+
+ if(!ade_get_args(L, "o|i", l_Order.GetPtr(&ohp), &priority))
+ return ade_set_error(L, "i", 0);
+
+ if(!ohp->IsValid())
+ return ade_set_error(L, "i", 0);
+
+ if(ADE_SETTING_VAR) {
+ ohp->aigp->priority = priority;
+ }
+
+ return ade_set_args(L, "i", ohp->aigp->priority);
+}
+
+ADE_FUNC(remove, l_Order, NULL, "Removes the given order from the ship's priority queue.", "boolean", "True if order was successfully removed, otherwise false or nil.")
+{
+ order_h *ohp = NULL;
+ if(!ade_get_args(L, "o", l_Order.GetPtr(&ohp)))
+ return ADE_RETURN_NIL;
+
+ if(!ohp->IsValid())
+ return ADE_RETURN_FALSE;
+
+ ai_info *aip = &Ai_info[Ships[ohp->objh.objp->instance].ai_index];
+
+ ai_remove_ship_goal(aip, ohp->odx);
+
+ return ADE_RETURN_TRUE;
+}
+
+ADE_FUNC(getType, l_Order, NULL, "Gets the type of the order.", "enumeration", "The type of the order as one of the ORDER_* enumerations.")
+{
+ order_h *ohp = NULL;
+ int eh_idx = -1;
+ if(!ade_get_args(L, "o", l_Order.GetPtr(&ohp)))
+ return ade_set_error(L, "o", l_Enum.Set(enum_h()));
+
+ if(!ohp->IsValid())
+ return ade_set_error(L, "o", l_Enum.Set(enum_h()));
+
+ switch(ohp->aigp->ai_mode){
+ case AI_GOAL_DESTROY_SUBSYSTEM:
+ case AI_GOAL_CHASE_WEAPON:
+ case AI_GOAL_CHASE:
+ eh_idx = LE_ORDER_ATTACK;
+ break;
+ case AI_GOAL_DOCK:
+ eh_idx = LE_ORDER_DOCK;
+ break;
+ case AI_GOAL_WAYPOINTS:
+ eh_idx = LE_ORDER_WAYPOINTS;
+ break;
+ case AI_GOAL_WAYPOINTS_ONCE:
+ eh_idx = LE_ORDER_WAYPOINTS_ONCE;
+ break;
+ case AI_GOAL_WARP:
+ eh_idx = LE_ORDER_DEPART;
+ break;
+ case AI_GOAL_FORM_ON_WING:
+ eh_idx = LE_ORDER_FORM_ON_WING;
+ break;
+ case AI_GOAL_UNDOCK:
+ eh_idx = LE_ORDER_UNDOCK;
+ break;
+ case AI_GOAL_GUARD:
+ eh_idx = LE_ORDER_GUARD;
+ break;
+ case AI_GOAL_DISABLE_SHIP:
+ eh_idx = LE_ORDER_DISABLE;
+ break;
+ case AI_GOAL_DISARM_SHIP:
+ eh_idx = LE_ORDER_DISARM;
+ break;
+ case AI_GOAL_CHASE_ANY:
+ eh_idx = LE_ORDER_ATTACK_ANY;
+ break;
+ case AI_GOAL_IGNORE_NEW:
+ case AI_GOAL_IGNORE:
+ eh_idx = LE_ORDER_IGNORE;
+ break;
+ case AI_GOAL_EVADE_SHIP:
+ eh_idx = LE_ORDER_EVADE;
+ break;
+ case AI_GOAL_STAY_NEAR_SHIP:
+ eh_idx = LE_ORDER_STAY_NEAR;
+ break;
+ case AI_GOAL_KEEP_SAFE_DISTANCE:
+ eh_idx = LE_ORDER_KEEP_SAFE_DISTANCE;
+ break;
+ case AI_GOAL_REARM_REPAIR:
+ eh_idx = LE_ORDER_REARM;
+ break;
+ case AI_GOAL_STAY_STILL:
+ eh_idx = LE_ORDER_STAY_STILL;
+ break;
+ case AI_GOAL_PLAY_DEAD:
+ eh_idx = LE_ORDER_PLAY_DEAD;
+ break;
+ case AI_GOAL_FLY_TO_SHIP:
+ eh_idx = LE_ORDER_FLY_TO;
+ break;
+ case AI_GOAL_CHASE_WING:
+ eh_idx = LE_ORDER_ATTACK_WING;
+ break;
+ case AI_GOAL_GUARD_WING:
+ eh_idx = LE_ORDER_GUARD_WING;
+ break;
+ }
+
+ return ade_set_args(L, "o", l_Enum.Set(eh_idx));
+}
+
+ADE_VIRTVAR(Target, l_Order, "object", "Target of the order. Value may also be a deriviative of the 'object' class, such as 'ship'.", "object", "Target object or invalid object handle if order handle is invalid or order requires no target.")
+{
+ order_h *ohp = NULL;
+ object_h *newh = NULL;
+ ai_info *aip = NULL;
+ waypoint_list *wpl = NULL;
+ int shipnum = -1, objnum = -1;
+ if(!ade_get_args(L, "o|o", l_Order.GetPtr(&ohp), l_Object.GetPtr(&newh)))
+ return ade_set_error(L, "o", l_Object.Set(object_h()));
+
+ if(!ohp->IsValid())
+ return ade_set_error(L, "o", l_Object.Set(object_h()));
+
+ aip = &Ai_info[Ships[ohp->objh.objp->instance].ai_index];
+
+ if(ADE_SETTING_VAR){
+ if(newh->IsValid()){
+ switch(ohp->aigp->ai_mode){
+ case AI_GOAL_DESTROY_SUBSYSTEM:
+ case AI_GOAL_CHASE:
+ case AI_GOAL_FORM_ON_WING:
+ case AI_GOAL_GUARD:
+ case AI_GOAL_DISABLE_SHIP:
+ case AI_GOAL_DISARM_SHIP:
+ case AI_GOAL_IGNORE_NEW:
+ case AI_GOAL_IGNORE:
+ case AI_GOAL_EVADE_SHIP:
+ case AI_GOAL_STAY_NEAR_SHIP:
+ case AI_GOAL_KEEP_SAFE_DISTANCE:
+ case AI_GOAL_FLY_TO_SHIP:
+ case AI_GOAL_STAY_STILL:
+ if ((newh->objp->type == OBJ_SHIP) && !stricmp(Ships[newh->objp->instance].ship_name, ohp->aigp->target_name)){
+ ohp->aigp->target_name = Ships[newh->objp->instance].ship_name;
+ ohp->aigp->time = Missiontime;
+ if(ohp->odx == 0) {
+ aip->ok_to_target_timestamp = timestamp(0);
+ set_target_objnum(aip, OBJ_INDEX(newh->objp));
+ }
+ }
+ break;
+ case AI_GOAL_CHASE_WEAPON:
+ if ((newh->objp->type == OBJ_WEAPON) && (ohp->aigp->target_signature != newh->sig)){
+ ohp->aigp->target_instance = newh->objp->instance;
+ ohp->aigp->target_signature = Weapons[newh->objp->instance].objnum;
+ ohp->aigp->time = Missiontime;
+ if(ohp->odx == 0) {
+ aip->ok_to_target_timestamp = timestamp(0);
+ set_target_objnum(aip, OBJ_INDEX(newh->objp));
+ }
+ }
+ break;
+ case AI_GOAL_WAYPOINTS:
+ case AI_GOAL_WAYPOINTS_ONCE:
+ if (newh->objp->type == OBJ_WAYPOINT){
+ waypoint_list *wpl =  find_waypoint_list_with_instance(newh->objp->instance);
+ if (!stricmp(wpl->get_name(),ohp->aigp->target_name)){
+ ohp->aigp->target_name = wpl->get_name();
+ ohp->aigp->time = Missiontime;
+ if(ohp->odx == 0) {
+ int flags = 0;
+ if ( ohp->aigp->ai_mode == AI_GOAL_WAYPOINTS)
+ flags |= WPF_REPEAT;
+ ai_start_waypoints(ohp->objh.objp, wpl, flags);
+ }
+ }
+ }
+ break;
+ case AI_GOAL_CHASE_WING:
+ if((newh->objp->type == OBJ_SHIP) && !stricmp(Ships[newh->objp->instance].ship_name, ohp->aigp->target_name)){
+ ship *shipp = &Ships[newh->objp->instance];
+ if (shipp->wingnum != -1){
+ ohp->aigp->target_name = Wings[shipp->wingnum].name;
+ if(ohp->odx == 0) {
+ aip->ok_to_target_timestamp = timestamp(0);
+ ai_attack_wing(ohp->objh.objp,shipp->wingnum);
+ }
+ }
+ }
+ break;
+ case AI_GOAL_GUARD_WING:
+ if((newh->objp->type == OBJ_SHIP) && !stricmp(Ships[newh->objp->instance].ship_name, ohp->aigp->target_name)){
+ ship *shipp = &Ships[newh->objp->instance];
+ if (shipp->wingnum != -1){
+ ohp->aigp->target_name = Wings[shipp->wingnum].name;
+ if(ohp->odx == 0) {
+ aip->ok_to_target_timestamp = timestamp(0);
+ ai_set_guard_wing(ohp->objh.objp,shipp->wingnum);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ switch(ohp->aigp->ai_mode){
+ case AI_GOAL_DESTROY_SUBSYSTEM:
+ case AI_GOAL_CHASE:
+ case AI_GOAL_DOCK:
+ case AI_GOAL_FORM_ON_WING:
+ case AI_GOAL_GUARD:
+ case AI_GOAL_DISABLE_SHIP:
+ case AI_GOAL_DISARM_SHIP:
+ case AI_GOAL_IGNORE_NEW:
+ case AI_GOAL_IGNORE:
+ case AI_GOAL_EVADE_SHIP:
+ case AI_GOAL_STAY_NEAR_SHIP:
+ case AI_GOAL_KEEP_SAFE_DISTANCE:
+ case AI_GOAL_REARM_REPAIR:
+ case AI_GOAL_FLY_TO_SHIP:
+ case AI_GOAL_UNDOCK:
+ shipnum = ship_name_lookup(ohp->aigp->target_name);
+ objnum = Ships[shipnum].objnum;
+ break;
+ case AI_GOAL_CHASE_WEAPON:
+ objnum = Weapons[ohp->aigp->target_instance].objnum;
+ break;
+ case AI_GOAL_WAYPOINTS:
+ case AI_GOAL_WAYPOINTS_ONCE:
+ wpl = find_matching_waypoint_list(ohp->aigp->target_name);
+ if(ohp->odx == 0) {
+ objnum = aip->wp_list->get_waypoints()[aip->wp_index].get_objnum();
+ } else {
+ objnum = wpl->get_waypoints().front().get_objnum();
+ }
+ break;
+ case AI_GOAL_STAY_STILL:
+ shipnum = ship_name_lookup(ohp->aigp->target_name);
+ if (shipnum != -1){
+ objnum = Ships[shipnum].objnum;
+ break;
+ }
+ case AI_GOAL_CHASE_WING:
+ case AI_GOAL_GUARD_WING:
+ int wingnum = wing_name_lookup(ohp->aigp->target_name);
+ if (Wings[wingnum].current_count > 0){
+ shipnum = Wings[wingnum].ship_index[0];
+ objnum = Ships[shipnum].objnum;
+ }
+ break;
+ }
+
+ return ade_set_object_with_breed(L, objnum);
+}
+
+
+ADE_VIRTVAR(TargetSubsystem, l_Order, "subsystem", "Target subsystem of the order.", "subsystem", "Target subsystem, or invalid subsystem handle if order handle is invalid or order requires no subsystem target.")
+{
+ order_h *ohp = NULL;
+ ship_subsys_h *newh = NULL;
+ ai_info *aip = NULL;
+ object *objp = NULL;
+ if(!ade_get_args(L, "o|o", l_Order.GetPtr(&ohp), l_Subsystem.GetPtr(&newh)))
+ return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h()));
+
+ if(!ohp->IsValid())
+ return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h()));
+
+ aip = &Ai_info[Ships[ohp->objh.objp->instance].ai_index];
+
+ if(ADE_SETTING_VAR)
+ {
+ if(newh->IsValid() && (ohp->aigp->ai_mode == AI_GOAL_DESTROY_SUBSYSTEM))
+ {
+ objp = &Objects[newh->ss->parent_objnum];
+ if(!stricmp(Ships[objp->instance].ship_name, ohp->aigp->target_name)) {
+ ohp->aigp->target_name = Ships[objp->instance].ship_name;
+ ohp->aigp->time = Missiontime;
+ if(ohp->odx == 0) {
+ aip->ok_to_target_timestamp = timestamp(0);
+ set_target_objnum(aip, OBJ_INDEX(objp));
+ }
+ }
+ ohp->aigp->ai_submode = ship_get_subsys_index( &Ships[objp->instance], newh->ss->system_info->subobj_name );
+ if(ohp->odx == 0) {
+ set_targeted_subsys(aip, newh->ss, OBJ_INDEX(objp));
+ }
+ if (aip == Player_ai) {
+ Ships[newh->ss->parent_objnum].last_targeted_subobject[Player_num] = newh->ss;
+ }
+ }
+ }
+
+ if(ohp->aigp->ai_mode == AI_GOAL_DESTROY_SUBSYSTEM){
+ return ade_set_args(L, "o", l_Subsystem.Set(ship_subsys_h(&Objects[Ships[ship_name_lookup(ohp->aigp->target_name)].objnum], ship_get_indexed_subsys(&Ships[ship_name_lookup(ohp->aigp->target_name)],ohp->aigp->ai_submode))));
+ } else {
+ return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h()));
+ }
+}
+
+ADE_FUNC(isValid, l_Order, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
+{
+ order_h *ohp = NULL;
+ if(!ade_get_args(L, "o", l_Order.GetPtr(&ohp)))
+ return ADE_RETURN_NIL;
+
+ return ade_set_args(L, "b", ohp->IsValid());
+}
+
+//**********HANDLE: shiporders
+ade_obj<object_h> l_ShipOrders("shiporders", "Ship orders");
+
+ADE_FUNC(__len, l_ShipOrders, NULL, "Number of ship orders", "number", "Number of ship orders, or 0 if handle is invalid")
+{
+ object_h *objh = NULL;
+ if(!ade_get_args(L, "o", l_ShipOrders.GetPtr(&objh)))
+ return ade_set_error(L, "i", 0);
+
+ if(!objh->IsValid() || objh->objp->type != OBJ_SHIP || Ships[objh->objp->instance].ai_index < 0)
+ return ade_set_error(L, "i", 0);
+
+ return ade_set_args(L, "i", ai_goal_num(&Ai_info[Ships[objh->objp->instance].ai_index].goals[0]));
+}
+
+ADE_INDEXER(l_ShipOrders, "number Index", "Array of ship orders", "order", "Order, or invalid order handle on failure")
+{
+ object_h *objh = NULL;
+ int i;
+
+ if (!ade_get_args(L, "oi", l_ShipOrders.GetPtr(&objh), &i))
+ return ade_set_error(L, "o", l_Order.Set(order_h()));
+
+ i--; //Lua->FS2
+
+ if (!objh->IsValid() || i < 0 || i >= MAX_AI_GOALS)
+ return ade_set_error(L, "o", l_Order.Set(order_h()));
+
+ ai_info *aip = &Ai_info[Ships[objh->objp->instance].ai_index];
+
+ if (aip->goals[i].ai_mode != AI_GOAL_NONE)
+ return ade_set_args(L, "o", l_Order.Set(order_h(objh->objp, i)));
+ else
+ return ade_set_args(L, "o", l_Order.Set(order_h()));
+}
+
+ADE_FUNC(isValid, l_ShipOrders, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
+{
+ object_h *oh;
+ if(!ade_get_args(L, "o", l_ShipOrders.GetPtr(&oh)))
+ return ADE_RETURN_NIL;
+
+ return ade_set_args(L, "b", oh->IsValid());
+}
+
+
+
 //**********HANDLE: shiptextures
 ade_obj<object_h> l_ShipTextures("shiptextures", "Ship textures handle");
 
@@ -8587,6 +8870,24 @@
  return ade_set_args(L, "i", Ships[objh->objp->instance].weapon_recharge_index);
 }
 
+ADE_VIRTVAR(Orders, l_Ship, "shiporders", "Array of ship orders", "shiporders", "Ship orders, or invalid handle if ship handle is invalid")
+{
+ object_h *objh = NULL;
+ object_h *newh = NULL;
+ if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_ShipOrders.GetPtr(&newh)))
+ return ade_set_error(L, "o", l_ShipOrders.Set(object_h()));
+
+ if(!objh->IsValid())
+ return ade_set_error(L, "o", l_ShipOrders.Set(object_h()));;
+
+ if(ADE_SETTING_VAR)
+ {
+ LuaError(L, "Attempted to use incomplete feature: Ai orders copy. Use giveOrder instead");
+ }
+
+ return ade_set_args(L, "o", l_ShipOrders.Set(object_h(objh->objp)));
+}
+
 ADE_FUNC(kill, l_Ship, "[object Killer]", "Kills the ship. Set \"Killer\" to the ship you are killing to self-destruct", "boolean", "True if successful, false or nil otherwise")
 {
  object_h *victim,*killer=NULL;
@@ -8947,6 +9248,35 @@
  }
  break;
  }
+ case LE_ORDER_ATTACK_WING:
+ {
+ if(tgh_valid && tgh->objp->type == OBJ_SHIP)
+ {
+ ship *shipp = &Ships[tgh->objp->instance];
+ if (shipp->wingnum != -1)
+ {
+ ai_mode = AI_GOAL_CHASE_WING;
+ ai_shipname = Wings[shipp->wingnum].name;
+ ai_submode = SM_ATTACK;
+ }
+ }
+ break;
+ }
+ case LE_ORDER_GUARD_WING:
+ {
+ if(tgh_valid && tgh->objp->type == OBJ_SHIP)
+ {
+ ship *shipp = &Ships[tgh->objp->instance];
+ if (shipp->wingnum != -1)
+ {
+ ai_mode = AI_GOAL_GUARD_WING;
+ ai_shipname = Wings[shipp->wingnum].name;
+ ai_submode = AIS_GUARD_STATIC;
+ }
+ }
+
+ break;
+ }
  }
 
  //Nothing got set!
« Last Edit: January 09, 2014, 07:15:49 pm by Admiral MS »
Here goes scripting and copy paste coding
Freespace RTS Mod
Checkpoint/Shipsaveload script

 

Offline mjn.mixael

  • Cutscene Master
  • 212
  • Chopped liver
    • Steam
    • Twitter
Re: Extended Afterburner use by AI (waypoints)
AI Profiles table flag to default this to on.
Cutscene Upgrade Project - Mainhall Remakes - Between the Ashes
Youtube Channel - P3D Model Box
Between the Ashes is looking for committed testers, PM me for details.
Freespace Upgrade Project See what's happening.

 
Re: Extended Afterburner use by AI
Here is a new patch that includes not only the use of afterburners when flying waypoints or in formation but also during approach of a guard target (small ships and capships) or a hostile capship attack target.
Activation is by using the alter-ship-flag sexp with the new free-afterburner-use flag.
For difficulty scaling:
Guard and attack afterburner consider recharge rate and afterburner use factor, waypoint flying only recharge rate to produce reliable results.


And ai_formation() is stupid. Too many cases with too many hardcoded values.

[attachment deleted by ninja]
« Last Edit: April 24, 2013, 07:13:28 am by Admiral MS »
Here goes scripting and copy paste coding
Freespace RTS Mod
Checkpoint/Shipsaveload script

 

Offline Fury

  • The Curmudgeon
  • 213
Re: Extended Afterburner use by AI
How does afterburner charge level play into AI behavior, if for example a mod uses afterburners that do not recharge?

 
Re: Extended Afterburner use by AI
For attack and guard orders the ai should use it until afterburner fuel is emtpy or below a certain percentage - like it does currently for all cases (I think).

The waypoint flying in my patch does an average speed calculation if the ships are in a wing that includes the recharge rate and if it is 0 they won't use afterburners. Single ships flying waypoints will use them until fuel is depleted.
Here goes scripting and copy paste coding
Freespace RTS Mod
Checkpoint/Shipsaveload script

  
Re: [Code review] Admiral MS' features for post-3.7.0
Modified topic like the one zookeeper made and added some scripting features.


Scripting function to get the wing of a ship, the wing section had to be moved above the ships section to give it access to l_Wing
Code: [Select]
Index: code/parse/lua.cpp
===================================================================
--- code/parse/lua.cpp (revision 10284)
+++ code/parse/lua.cpp (working copy)
@@ -7820,6 +7820,54 @@
  return ade_set_args(L, "b", cdh->isValid());
 }
 
+//**********HANDLE: Wing
+ade_obj<int> l_Wing("wing", "Wing handle");
+
+ADE_INDEXER(l_Wing, "number Index", "Array of ships in the wing", "ship", "Ship handle, or invalid ship handle if index is invawing handle is invalid")
+{
+ int wdx;
+ int sdx;
+ object_h *ndx=NULL;
+ if(!ade_get_args(L, "oi|o", l_Wing.Get(&wdx), &sdx, l_Ship.GetPtr(&ndx)))
+ return ade_set_error(L, "o", l_Ship.Set(object_h()));
+
+ if(sdx < 1 || sdx > Wings[wdx].current_count) {
+ return ade_set_error(L, "o", l_Ship.Set(object_h()));
+ }
+
+ //Lua-->FS2
+ sdx--;
+
+ if(ADE_SETTING_VAR && ndx != NULL && ndx->IsValid()) {
+ Wings[wdx].ship_index[sdx] = ndx->objp->instance;
+ }
+
+ return ade_set_args(L, "o", l_Ship.Set(object_h(&Objects[Ships[Wings[wdx].ship_index[sdx]].objnum])));
+}
+
+ADE_FUNC(__len, l_Wing, NULL, "Number of wings in mission", "number", "Number of wings in mission")
+{
+ int wdx;
+ if(!ade_get_args(L, "o", l_Wing.Get(&wdx)))
+ return ade_set_error(L, "i", NULL);
+
+ return ade_set_args(L, "i", Wings[wdx].current_count);
+}
+
+ADE_VIRTVAR(Name, l_Wing, "string", "Name of Wing", "string", "Wing name, or empty string if handle is invalid")
+{
+ int wdx;
+ char *s = NULL;
+ if ( !ade_get_args(L, "o|s", l_Wing.Get(&wdx), &s) )
+ return ade_set_error(L, "s", "");
+
+ if(ADE_SETTING_VAR && s != NULL) {
+ strncpy(Wings[wdx].name, s, sizeof(Wings[wdx].name)-1);
+ }
+
+ return ade_set_args(L, "s", Wings[wdx].name);
+}
+
 //**********HANDLE: Ship
 ade_obj<object_h> l_Ship("ship", "Ship handle", &l_Object);
 
@@ -9264,6 +9312,21 @@
  }
 }
 
+ADE_FUNC(getWing, l_Ship, NULL, "Returns the ship's wing", "Wing", "Wing handle, or invalid wing handle if ship is not part of a wing")
+{
+ object_h *objh = NULL;
+ ship *shipp = NULL;
+
+ if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
+ return ade_set_error(L, "o", l_Wing.Set(-1));
+
+ if(!objh->IsValid())
+ return ade_set_error(L, "o", l_Wing.Set(-1));
+
+ shipp = &Ships[objh->objp->instance];
+ return ade_set_args(L, "o", l_Wing.Set(shipp->wingnum));
+}
+
 //**********HANDLE: Weapon
 ade_obj<object_h> l_Weapon("weapon", "Weapon handle", &l_Object);
 
@@ -9936,39 +9999,6 @@
  return ade_set_args(L, "o", l_Vector.Set(inf.dir_b));
 }
 
-//**********HANDLE: Wing
-ade_obj<int> l_Wing("wing", "Wing handle");
-
-ADE_INDEXER(l_Wing, "number Index", "Array of ships in the wing", "ship", "Ship handle, or invalid ship handle if index is invawing handle is invalid")
-{
- int wdx;
- int sdx;
- object_h *ndx=NULL;
- if(!ade_get_args(L, "oi|o", l_Wing.Get(&wdx), &sdx, l_Ship.GetPtr(&ndx)))
- return ade_set_error(L, "o", l_Ship.Set(object_h()));
-
- if(sdx < 1 || sdx > Wings[wdx].current_count) {
- return ade_set_error(L, "o", l_Ship.Set(object_h()));
- }
-
- //Lua-->FS2
- sdx--;
-
- if(ADE_SETTING_VAR && ndx != NULL && ndx->IsValid()) {
- Wings[wdx].ship_index[sdx] = ndx->objp->instance;
- }
-
- return ade_set_args(L, "o", l_Ship.Set(object_h(&Objects[Ships[Wings[wdx].ship_index[sdx]].objnum])));
-}
-
-ADE_FUNC(__len, l_Wing, NULL, "Number of wings in mission", "number", "Number of wings in mission")
-{
- int wdx;
- if(!ade_get_args(L, "o", l_Wing.Get(&wdx)))
- return ade_set_error(L, "i", NULL);
-
- return ade_set_args(L, "i", Wings[wdx].current_count);
-}
 //**********HANDLE: Player
 ade_obj<int> l_Player("player", "Player handle");
 

Scripting function to get the waypoint-list of a waypoint
Code: [Select]
Index: code/parse/lua.cpp
===================================================================
--- code/parse/lua.cpp (revision 10284)
+++ code/parse/lua.cpp (working copy)
@@ -6443,12 +6443,28 @@
 ADE_VIRTVAR(Name, l_WaypointList, "string", "Name of WaypointList", "string", "Waypointlist name, or empty string if handle is invalid")
 {
  waypointlist_h* wlh = NULL;
- if ( !ade_get_args(L, "o", l_WaypointList.GetPtr(&wlh)) ) {
- return ade_set_error( L, "o", l_Waypoint.Set( object_h() ) );
+ char *s = NULL;
+ if ( !ade_get_args(L, "o|s", l_WaypointList.GetPtr(&wlh), &s) ) {
+ return ade_set_error(L, "s", "");
  }
+
+ if(ADE_SETTING_VAR && s != NULL) {
+ wlh->wlp->set_name(s);
+ strcpy_s(wlh->name,s);
+ }
+
  return ade_set_args( L, "s", wlh->name);
 }
 
+ADE_FUNC(isValid, l_WaypointList, NULL, "Return if this waypointlist handle is valid", "boolean", "true if valid false otherwise")
+{
+ waypointlist_h* wlh = NULL;
+ if ( !ade_get_args(L, "o", l_WaypointList.GetPtr(&wlh)) ) {
+ return ADE_RETURN_FALSE;
+ }
+ return ade_set_args(L, "b", wlh != NULL && wlh->IsValid());
+}
+
 //WMC - Waypoints are messed. Gonna leave this for later.
 /*
 ade_lib l_WaypointList_Waypoints("Waypoints", &l_Waypoint, NULL, NULL);
@@ -6492,6 +6508,27 @@
  return ade_set_args(L, "i", count);
 }*/
 
+ADE_FUNC(getList, l_Waypoint, NULL, "Returns the waypoint list", "waypointlist", "waypointlist handle or invalid handle if waypoint was invalid")
+{
+ object_h *oh = NULL;
+ waypointlist_h wpl;
+ waypoint_list *wp_list = NULL;
+ if(!ade_get_args(L, "o", l_Waypoint.GetPtr(&oh)))
+ return ade_set_error(L, "o", l_WaypointList.Set(waypointlist_h()));
+
+ if(oh->IsValid() && oh->objp->type == OBJ_WAYPOINT) {
+ wp_list = find_waypoint_list_with_instance(oh->objp->instance);
+ if(wp_list != NULL)
+ wpl = waypointlist_h(wp_list);
+ }
+
+ if (wpl.IsValid()) {
+ return ade_set_args(L, "o", l_WaypointList.Set(wpl));
+ }
+
+ return ade_set_error(L, "o", l_WaypointList.Set(waypointlist_h()));
+}
+
 //**********HANDLE: Weaponbank
 #define SWH_NONE 0
 #define SWH_PRIMARY 1
« Last Edit: January 09, 2014, 07:17:28 pm by Admiral MS »
Here goes scripting and copy paste coding
Freespace RTS Mod
Checkpoint/Shipsaveload script

 

Offline niffiwan

  • 211
  • Eluder Class
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
:bump:

I've had a look at the 1st patch (ADE_FUNC(isTargetInFOV...) & I've just got a few minor questions (well, nitpicks really):

1) The return type is boolean, but there are three return values, ADE_RETURN_NIL / ADE_RETURN_TRUE / ADE_RETURN_FALSE.  Would it be clearer to replace ADE_RETURN_NIL with ADE_RETURN_FALSE (since they will evaluate to the same thing anyway?. i.e. int 0 == bool false?)

2) There's a spelling error in the description:
"true if in FOV, false if not or subsystem is no turret or nil on error"

That aside, looks good so if you can let me know what you think about point one, I'll commit it.
Creating a fs2_open.log | Red Alert Bug = Hex Edit | MediaVPs 2014: Bigger HUD gauges | 32bit libs for 64bit Ubuntu
----
Debian Packages (testing/unstable): Freespace2 | wxLauncher
----
m|m: I think I'm suffering from Stockholm syndrome. Bmpman is starting to make sense and it's actually written reasonably well...

 
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
1) It seemed to me that many scripting functions return NIL instead of FALSE when something is wrong. In theory someone might use a check for false but usually it won't make any difference.

2) Changed description a bit
Here goes scripting and copy paste coding
Freespace RTS Mod
Checkpoint/Shipsaveload script

 

Offline niffiwan

  • 211
  • Eluder Class
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
thanks - I'll commit that one tonight, and try to get the rest reviewed as well.
Creating a fs2_open.log | Red Alert Bug = Hex Edit | MediaVPs 2014: Bigger HUD gauges | 32bit libs for 64bit Ubuntu
----
Debian Packages (testing/unstable): Freespace2 | wxLauncher
----
m|m: I think I'm suffering from Stockholm syndrome. Bmpman is starting to make sense and it's actually written reasonably well...

 

Offline niffiwan

  • 211
  • Eluder Class
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
I've finished a review of the 2nd patch now, took me longer than expected :)

Please let me know what you think about my comments below.

===============================
For: struct order_h

The constructor order_h() doesn't init aigp?

Should IsValid() also check if aigp == NULL?

Should the comment the end of the line be removed?
Code: [Select]
if(objh.IsValid() && objh.objp->type == OBJ_SHIP && n_odx > -1 && n_odx < MAX_AI_GOALS)//&& odx > -1

===============================
For: ADE_VIRTVAR(Priority, l_Order

Should the input var priority be checked that it's in a valid range?
e.g.
Code: [Select]
if ((newh->objp->type == OBJ_SHIP)...
    Assertion(newh->objp->instance >= 0 && newh->objp->instance < MAX_SHIPS, ... );
    (use newh->objp->instance as an array index)

(with relevant ranges substitued for OBJ_WEAPON / OBJ_WAYPOINT in other cases)

===============================
For: ADE_VIRTVAR(Target, l_Order

Should the input object index (newh->objp->instance) be range checked before use?

There are some commented out code that should be removed?

===============================
For: ADE_VIRTVAR(TargetSubsystem, l_Order,

Should these (newh->ss->parent_objnum & objp->instance) be range checked before use?

There's some more commented out code that should be removed?

Is this comment still relevant?
// TO DO: check the strange crash for this

===============================
For: ADE_VIRTVAR(Orders, l_Ship,

It looks like current object and the (admittedly not-implemented) input variable are being saved to the same object? Is this intentional?
object_h *objh;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_ShipOrders.GetPtr(&objh)))

===============================
edit: one more thing, gcc is logging this compile error.  Should ->get_objnum() just be removed?
Code: [Select]
parse/lua.cpp:7643:26: error: base operand of ‘->’ is not a pointer
    objnum = aip->wp_index->get_objnum();
« Last Edit: October 11, 2013, 01:28:26 am by niffiwan »
Creating a fs2_open.log | Red Alert Bug = Hex Edit | MediaVPs 2014: Bigger HUD gauges | 32bit libs for 64bit Ubuntu
----
Debian Packages (testing/unstable): Freespace2 | wxLauncher
----
m|m: I think I'm suffering from Stockholm syndrome. Bmpman is starting to make sense and it's actually written reasonably well...

 

Offline niffiwan

  • 211
  • Eluder Class
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
Reviewed the 3rd patch, only one question this time :)

In ADE_FUNC(getWing, l_Ship..., why is the returned wing number being decremented?  Won't this change the wing that the ship is a member of?

Code: [Select]
return ade_set_args(L, "o", l_Wing.Set(shipp->wingnum--));
Creating a fs2_open.log | Red Alert Bug = Hex Edit | MediaVPs 2014: Bigger HUD gauges | 32bit libs for 64bit Ubuntu
----
Debian Packages (testing/unstable): Freespace2 | wxLauncher
----
m|m: I think I'm suffering from Stockholm syndrome. Bmpman is starting to make sense and it's actually written reasonably well...

 

Offline niffiwan

  • 211
  • Eluder Class
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
And the last one:

In, ADE_VIRTVAR(Name, l_WaypointList,, when setting a new name, will wlh->wlp->m_name be different to wlh->name at the end of the function?  I can't see how the name would be copied from wlh->wlp.m_name into wlh->name.

Aside from my comments, the last three all look good.  If you can let me know what you think about my questions, I can commit the patches for you.
Creating a fs2_open.log | Red Alert Bug = Hex Edit | MediaVPs 2014: Bigger HUD gauges | 32bit libs for 64bit Ubuntu
----
Debian Packages (testing/unstable): Freespace2 | wxLauncher
----
m|m: I think I'm suffering from Stockholm syndrome. Bmpman is starting to make sense and it's actually written reasonably well...

 
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
 :bump:
Three months later I finally got some time for this. All patches modified to run with latest trunk, changed most things niffiwan commented on and tested them again.

Quote
Please let me know what you think about my comments below.

===============================
For: struct order_h

The constructor order_h() doesn't init aigp?

Should IsValid() also check if aigp == NULL?

Should the comment the end of the line be removed?
Code: [Select]
if(objh.IsValid() && objh.objp->type == OBJ_SHIP && n_odx > -1 && n_odx < MAX_AI_GOALS)//&& odx > -1
Added the aigp init and check, removed the comment.
Quote
===============================
For: ADE_VIRTVAR(Priority, l_Order

Should the input var priority be checked that it's in a valid range?
e.g.
Code: [Select]
if ((newh->objp->type == OBJ_SHIP)...
    Assertion(newh->objp->instance >= 0 && newh->objp->instance < MAX_SHIPS, ... );
    (use newh->objp->instance as an array index)

(with relevant ranges substitued for OBJ_WEAPON / OBJ_WAYPOINT in other cases)
Didn't find anything in the ai code that has limitations towards the priority value as long as the input is an integer (which the LUA code checks).
Quote

===============================
For: ADE_VIRTVAR(Target, l_Order

Should the input object index (newh->objp->instance) be range checked before use?

There are some commented out code that should be removed?

===============================
For: ADE_VIRTVAR(TargetSubsystem, l_Order,

Should these (newh->ss->parent_objnum & objp->instance) be range checked before use?

There's some more commented out code that should be removed?

Is this comment still relevant?
// TO DO: check the strange crash for this
As the LUA code checks for the object validity the instance shouldn't be bad value with the other checks provided. If you still think it's necessary I have to add something.
Removed commented out code.
Quote

===============================
For: ADE_VIRTVAR(Orders, l_Ship,

It looks like current object and the (admittedly not-implemented) input variable are being saved to the same object? Is this intentional?
object_h *objh;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_ShipOrders.GetPtr(&objh))) ]
Not intentional: Changed it to another object to be safe.
Quote

===============================
edit: one more thing, gcc is logging this compile error.  Should ->get_objnum() just be removed?
Code: [Select]
parse/lua.cpp:7643:26: error: base operand of ‘->’ is not a pointer
    objnum = aip->wp_index->get_objnum();
]
I remember changing this a long time ago. It seems like I lost the last version of all patches at some point. Fixed it to get the right value.


Quote
Reviewed the 3rd patch, only one question this time :)

In ADE_FUNC(getWing, l_Ship..., why is the returned wing number being decremented?  Won't this change the wing that the ship is a member of?

Code: [Select]
return ade_set_args(L, "o", l_Wing.Set(shipp->wingnum--));
Probably an old patch as it causes a game crash. Removed the --.

Quote
And the last one:

In, ADE_VIRTVAR(Name, l_WaypointList,, when setting a new name, will wlh->wlp->m_name be different to wlh->name at the end of the function?  I can't see how the name would be copied from wlh->wlp.m_name into wlh->name.

Aside from my comments, the last three all look good.  If you can let me know what you think about my questions, I can commit the patches for you.
Fixed.
Here goes scripting and copy paste coding
Freespace RTS Mod
Checkpoint/Shipsaveload script

 

Offline niffiwan

  • 211
  • Eluder Class
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
Great - and committed in r10295 - 10297  :)

I made one minor change in 10295 as waypoint_list *wpl was re-declared in this check (i.e. gcc warned about variable shadowing); seemed like a trivial change to make but let me know if you disagree and I will fix it.
Code: [Select]
case AI_GOAL_WAYPOINTS_ONCE:
        if (newh->objp->type == OBJ_WAYPOINT){
                wpl = find_waypoint_list_with_instance(newh->objp->instance);
Creating a fs2_open.log | Red Alert Bug = Hex Edit | MediaVPs 2014: Bigger HUD gauges | 32bit libs for 64bit Ubuntu
----
Debian Packages (testing/unstable): Freespace2 | wxLauncher
----
m|m: I think I'm suffering from Stockholm syndrome. Bmpman is starting to make sense and it's actually written reasonably well...

 
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
Great - and committed in r10295 - 10297  :)

I made one minor change in 10295 as waypoint_list *wpl was re-declared in this check (i.e. gcc warned about variable shadowing); seemed like a trivial change to make but let me know if you disagree and I will fix it.
Code: [Select]
case AI_GOAL_WAYPOINTS_ONCE:
        if (newh->objp->type == OBJ_WAYPOINT){
                wpl = find_waypoint_list_with_instance(newh->objp->instance);
The change is ok. Seems to be an oversight on my part. Not sure if I missed a warning in Visual Studio or didn't get one.
Here goes scripting and copy paste coding
Freespace RTS Mod
Checkpoint/Shipsaveload script

 

Offline Zarax

  • 210
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
I apologize for necro-ing but as I understand this patch includes some changes to cap-ship AI that would be very useful, is there any test build that includes this and if yes how do I activate the new features?

Thanks!
The Best is Yet to Come

 

Offline niffiwan

  • 211
  • Eluder Class
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
The patches have been committed to trunk, so any recent nightly build (after Jan 14) will have the features.  As for activating them, they're mostly additional scripting commands that can be called from LUA scripts. They don't do anything by themselves, but they let you write a script that has more control over ships (I should probably let Admiral MS explain since he's actually using them).
Creating a fs2_open.log | Red Alert Bug = Hex Edit | MediaVPs 2014: Bigger HUD gauges | 32bit libs for 64bit Ubuntu
----
Debian Packages (testing/unstable): Freespace2 | wxLauncher
----
m|m: I think I'm suffering from Stockholm syndrome. Bmpman is starting to make sense and it's actually written reasonably well...

 
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
Besides one all added features are new or extended scripting functionality: ship:getWing(), waypoint:getList(), turret:isTargetInFOV(object) and access to the ai orders list of every ship. None of them do anything by themselves and they are mostly required to enable proper ai scripting in general.
isTargetInFOV is a function to check if a turret can hit something. At least my capship ai script would be impossible without this basic function.

The only feature that can be "activated" is free-afterburner-use that enables any ship to use afterburners while flying waypoints. Again this is not capship specific.

To create any good capship ai is up to scripters as it will probably never be hardcoded for a number of reasons. While I have a more or less working script it is still incomplete and I'm currently lacking free time to finish it.
Here goes scripting and copy paste coding
Freespace RTS Mod
Checkpoint/Shipsaveload script

 

Offline Zarax

  • 210
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
Oh, I was hoping for something a bit more friendly to less-experienced modders, guess I misunderstood your project a bit.

That said, thanks for your hard work!
The Best is Yet to Come

 
Re: [CODE REVIEW] Admiral MS' features for post-3.7.0
The script is very user friendly though. Thanks to these additions it can check for active attack orders where one capship attacks another, cancel the original order and take over ship movement and firing control.
Here goes scripting and copy paste coding
Freespace RTS Mod
Checkpoint/Shipsaveload script