UGX-Mods Login

or login with an authentication provider below
Sign In with Google
Sign In with Twitter
Sign In with Discord
Sign In with Steam
Sign In with Facebook
Sign In with Twitch

[WIP] Robot AI Companion

broken avatar :(
Created 6 years ago
by Archaicvirus
0 Members and 1 Guest are viewing this topic.
1,975 views
broken avatar :(
×
broken avatar :(
Location: usSouth Florida
Date Registered: 10 July 2016
Last active: 12 months ago
Posts
106
Respect
Forum Rank
Pack-a-Puncher
Primary Group
Donator ♥
My Groups
More
Signature
Let he who has not sinned cast the first stone.
×
Archaicvirus's Groups
Donator ♥ Benevolent Soul who has our eternal gratitude and exclusive access to betas and the donator section of the forum.
Archaicvirus's Contact & Social Links
If any mappers would like to use this robot, please comment below. I am willing to help you implement this in your map as well as adding features you may want

I've been working on this project for about a year, but off and on as I procrastinate and also have many behind the scenes unfinished projects. My main reason for posting this is I see a lot of potential with this mod, but I'm not that creative when it comes to mapping, so I thought I would see how many people/mappers are interested in using something like this in their map so all my work isn't for nothing. So far I have the state machine coded for the robot's animations, as well as a combat logic that handles enemy targeting and FX. Currently the robot will follow the player and dynamically shift focus on the nearest zombie within 500u of the robot.

Planned features:
  • The drone will pick up a single crawler and hold until killed, similar to leroy from BO2
  • The drone will focus on zombies closest to the owner, and have varied attacks, such as grabbing zombie's heads and pulling them off, grappling zombie's ankles & ragdoll-ing them, swinging them around & slamming
  • Adding in many more animations & creating a pool for each type. For example the default idle animation will have 5 variants that randomly play while in the idle state, so no animation will repeat
  • Scripting a complete buildable system for the robot, including the parts to initially acquire the drone, parts for it's laser-gun, and any parts for future mods/enhancements
  • The ability to revive downed player/teammates + buildable upgrade to keep all perks after robot revives
  • A cooldown system, to balance gameplay difficulty. I want this mod to be fun, not over-powered. Perhaps I could make a fuel system with a HUD for feedback (remaining fuel) Comment ideas on how to acquire fuel or other methods to balance!
  • Ability to grab nearby power-ups and bring them to the owner, similar to the BO2 tomahawk.
  • All ideas are welcome! Please comment below what you think.




Here is a video showing some of the earlier prototype models & animations



And here is the final prototype, fully textured & animation demo.



Here is an in-game demo of the current state of the robot's AI script



There are a few other prototypes that didn't get featured, but these should show the basic idea I had in the beginning and how it evolved as I gained experience with the various programs I used.

I have a decent script made that handles the robot's basic behaviors, and right now I'm re-doing the FX for the laser-fire -for the buildable laser-gun add-on. Everything in this project is custom, no borrowed scripts or models, textures or anything. The programs I used were mainly Blender for the modelling, Maya 2015 for the animations, Substance Painter 2 for the materials and Adobe Photoshop for the robot screen (face). If any mappers would like to use this, let me know below. I'd love to hear feedback, see if this thing is worth putting more time into or just putting on the shelf. Thanks for checking it out!

Here's the script so far if you're interested in how it works

Code Snippet
Plaintext
#using scripts\codescripts\struct;
#using scripts\shared\flag_shared;
#using scripts\shared\array_shared;
#using scripts\shared\util_shared;
#using scripts\shared\ai\zombie_utility;
#using scripts\zm\_zm_utility;
#using scripts\zm\_zm_score;
#using scripts\zm\_zm_unitrigger;
#using scripts\shared\math_shared;
#using scripts\zm\_zm_traps;
#using scripts\zm\_zm_weap_gravityspikes;
#using scripts\zm\_zm_spawner;
#using scripts\shared\hud_util_shared;
#using scripts\zm\_zm_powerups;
#using scripts\zm\crate_powerup_logic;
#using scripts\zm\vial_spawn;

#precache("fx", "custom/arch_robot_propulsion");
#precache("fx", "custom/arch_robot_laser");
//#precache("xanim", "arch_robot_anim_test");
//#precache("xanim", "arch_robot_dance");
//#precache("xanim", "arch_robot_hack_loop");
//#precache("xanim", "arch_robot_idle_passive");
//#precache("xanim", "arch_robot_idle");
#precache("xanim", "arch_robot_v7_idle");
#precache("xanim", "arch_robot_v7_combat_idle");
#precache("xanim", "arch_robot_v7_focus_atk");
#precache("xanim", "arch_robot_v7_laser_fire");
#precache("xanim", "arch_robot_v7_laser_aim_idle");
#precache("xmodel", "arch_robot_v7");
#precache("xmodel", "arch_robot_laser_gun");


#using_animtree("arch_drone_anims");

#namespace arch_drone_ai;

function init()
{
level flag::wait_till("all_players_connected");
level flag::init("inRadius", false);
level._effect["robot_propulsion"] = "custom/arch_robot_propulsion";
level._effect["robot_laser"] = "custom/arch_robot_laser";
trig = GetEnt("robot_test", "targetname");
trig SetCursorHint("HINT_NOICON");
trig SetHintString("Press &&1 to test anim");
trig thread follow();
}

function follow()
{
self waittill("trigger", player);
org = positionBot(player);
self.robot = Spawn("script_model", player.origin + org);
self.robot.angles = (0, -90, 0);
self.mover = Spawn("script_model", player.origin + org);
wait(0.2);
self.mover SetModel("tag_origin");
self.robot SetModel("arch_robot_v7");
self.robot EnableLinkTo();
self.robot LinkTo(self.mover, "tag_origin");
PlayFXOnTag(level._effect["robot_propulsion"], self.robot, "tag_origin");
self.robot.animState = "idle";
//self.robot SetScale(2.0);
self.robot UseAnimTree(#animtree);
wait(0.2);
tag = self.robot GetTagOrigin("tag_right_elbow");
self.robot.laser = Spawn("script_model", tag);
self.robot.laser SetModel("arch_robot_laser_gun");
self.robot.laser LinkTo(self.robot, "tag_right_elbow", (15, 0, 1.5), (0, -90, 0));
self.robot.laser Hide();
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_idle);
self thread robot_animState_watcher();
self thread robot_positioning_system(player);
while(1)
{
org = positionBot(player);
self.mover MoveTo(player.origin + org, .2);
wait(.2);
}
}

function positionBot(player)
{
//Forward and to the right of players view
f = AnglesToForward(player.angles) * 125;
org = AnglesToRight(player.angles) * 40 + (f + (0,0,75));
return org;
}

function robot_positioning_system(player)
{
while(1)
{
switch(self.robot.animState)
{
case "combat_idle":
case "focus_atk":
case "laser_atk":

//Decide robot's facing direction
zombies = GetAISpeciesArray("axis", "all");
closestZombie = ArrayGetClosest(self.mover.origin, zombies, 500);

//Target nearest enemy
tag = closestZombie GetTagOrigin("tag_eye");
vectorToFace = self.mover.origin - (tag[0], tag[1], tag[2] + 25);
//vectorToFace = self.mover.origin - (closestZombie.origin[0], closestZombie.origin[1], closestZombie.origin[2] + 120);
angle2Face = VectortoAngles(vectorToFace);
self.mover RotateTo((angle2Face[0], angle2Face[1] + 180, angle2Face[2]), .2);

break;

case "idle":
//If no zombies are in range, robot follows players direction
angles = player GetPlayerAngles();
self.mover RotateTo(angles, .2);
break;
}
wait(0.2);
}
}

function robot_animState_watcher()
{
while(1)
{
zombies = GetAISpeciesArray("axis", "all");
closest = ArrayGetClosest(self.robot.origin, zombies);
dist = Distance2D(self.robot.origin, closest.origin);
if(!isdefined(closest) || dist > 500 && self.robot.animState != "idle")
{
switch(self.robot.animState)
{
//void <entity> AnimScripted(<notify>,<origin>,<angles>,<animation>,[mode],[root],[rate],[blend],[lerp],[animation time],[is_scene_animation],[showPlayerWeaponInFirstPerson])
case "combat_idle":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_idle, "normal", %arch_robot_v7_combat_idle, 1, 1, 1);
break;

case "focus_atk":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_idle, "normal", %arch_robot_v7_laser_aim_idle, 1, .5, .5);
break;

case "laser_atk":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_idle, "normal", %arch_robot_v7_laser_fire, 1, .5, .5);
break;
}
self.robot.animState = "idle";
}

if(isdefined(closest) && dist < 500 && dist > 200 && self.robot.animState != "combat_idle")
{
switch(self.robot.animState)
{
case "idle":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_combat_idle, "normal", %arch_robot_v7_idle, 1, .5, .5);
break;

case "focus_atk":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_combat_idle, "normal", %arch_robot_v7_laser_aim_idle, 1, .5, .5);
break;

case "laser_atk":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_combat_idle, "normal", %arch_robot_v7_laser_fire, 1, .5, .5);
break;
}
self.robot.animState = "combat_idle";
}

if(isdefined(closest) && dist < 200 && dist > 50 && self.robot.animState != "focus_atk")
{
switch(self.robot.animState)
{
case "combat_idle":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_laser_aim_idle, "normal", %arch_robot_v7_combat_idle, 1, .5, .5);
break;

case "idle":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_laser_aim_idle, "normal", %arch_robot_v7_idle, 1, .5, .5);
break;

case "laser_atk":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_laser_aim_idle, "normal", %arch_robot_v7_laser_fire, 1, .5, .5);
break;
}
self.robot.animState = "focus_atk";
self thread projectile_logic();
}
/*
if(isdefined(closest) && dist < 50 && self.robot.animState != "laser_atk")
{
switch(self.robot.animState)
{
case "combat_idle":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_laser_fire, "normal", %arch_robot_v7_combat_idle, 2, .5, .5);
break;

case "idle":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_laser_fire, "normal", %arch_robot_v7_idle, 2, .5, .5);
break;

case "focus_atk":
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_laser_fire, "normal", %arch_robot_v7_laser_aim_idle, 2, .5, .5);
break;
}
self.robot.animState = "laser_atk";
}
*/
wait(.5);
}
}


function projectile_logic()
{
self.robot.laser Show();
while(self.robot.animState == "focus_atk")
{
zombies = GetAIArray("axis", "all");
zombie = ArrayGetClosest(self.mover.origin, zombies);
//laserOrg = Spawn("script_model");
//laserOrg SetModel("tag_origin");
PlayFXOnTag(level._effect["robot_laser"], self.mover, "tag_origin");
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_laser_fire, "normal", %arch_robot_v7_laser_aim_idle, 2, .05, .05);
//self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_laser_fire);
//PlayFXOnTag(level._effect["robot_laser"], self.mover, "tag_origin");

/*traceArray = BulletTrace(self.mover.origin, (zombie.origin[0], zombie.origin[1], zombie.origin[2] + 100), true, self.robot);
foreach(val in traceArray)
{
IPrintLnBold(val);
}
*/
self.robot waittill("anim_done");
wait(0.5);
self.robot AnimScripted("anim_done", self.robot.origin, self.robot.angles, %arch_robot_v7_laser_aim_idle, "normal", %arch_robot_v7_laser_fire, 1, .2, .2);
wait(1);
if(self.robot.animState != "focus_atk")
{
break;
}
}
self.robot.laser Hide();
}

function robot_combat_logic()
{
//void <entity> DoDamage(<health>,<source position>,[attacker],[inflictor],[hitloc],[mod],[dflags],[weapon],[infdestructible_piece_indexlictor],[forcePain])

}


Last Edit: December 13, 2017, 10:33:05 pm by Archaicvirus

 
Loading ...