Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - Archaicvirus

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

#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])

}


914 days ago
I've made a model of a crate, and made the animations for it to open and close it's lid in maya 2014. The problem is I don't really know the bone hierarchy that I need to follow. I tried making a bone called "tag_origin", then made it the parent of another bone called "tag_lid". I selected the lid of the crate, then hit bind>rigid to the "tag_lid" bone. I set the bottom of the crate to bind>rigid on the "tag_origin" bone. I can play both the animations in maya, and it looks fine, when the lid opens and closes, but in ape the box is sideways, and the animation doesn't play. Any help is appreciated.

*In APE I have the xanims set up as Type>delta. I enabled the option to view bones in the ape preview window, and I can see the tag_lid bone swinging open, but the lid isn't attached to the bone, I don't understand why because when playing the anim in maya it is attached and looks fine.
1081 days ago
I found this:
void <entity> IsPlayerSliding()

CATEGORY:
CLIENT/SERVER: Client
SUMMARY: Returns 1 if the player is currently sliding
EXAMPLE: if(ent IsPlayerSliding())

I wrote a simple while loop using this method in a csc file with an iprint, but it did not seem to work. Does anyone have experience using this?

I also found in the forums someone using GetVelocity() for slide detection, and that sort of works, but at certain times when the player is rotating their view and running, their velocity at either x or y reaches numbers that are close to the same velocity while sliding in any direction. It isn't really a fool proof way of 'detecting' a slide, so I'm just looking for a better way to execute this. Any help, much appreciated.
1096 days ago
I followed the directions precisely adding my custom perk, and the script is letting me buy the perk over and over until I max out my perk slots. I tried adding in manual checks to not let this happen for example:
function give_custom_perk()
{
// quick revive in solo gives an extra life
// give perk here
if(isdefined(self.hasFreezePerk) && self.hasFreezePerk == true) //Here is the check I make to stop spam buying
break;
self SetPerk("specialty_freeze");
self.hasFreezePerk = true;
self.has_custom_perks++;
self thread freeze_perk_shader::add_custom_perk_shader( self, "e115_vial_empty_shader" ); // CHANGE THIS TO YOUR PERK SHADER
trigger = GetEnt("specialty_freeze", "target"); // CHANGE THIS TO YOUR PERK MACHINE NAME
trigger SetHintStringForPlayer(self, "");
trigger SetInvisibleToPlayer(self);

}

I can't seem to remedy this issue, and I noticed on the original post shinged did not reply to this issue that two other members complained about, so hopefully someone else can provide some insight on why this is happening. The perk works fine, I can buy it, drink the bottle, and the perk effect is working, only issue being the ability to spam buy it.

EDIT* - After the check I make in this function, it still lets me spam buy the perk, but it will only show 1 perk shader. So the trigger is active for me until I have max perks.
1109 days ago
This is one of the custom xmodels I've made for a map I'm working on. The models I designed in blender. I textured everything from scratch in substance painter 2. Blender is free and has xmodel and xanim support via plugins. Substance painter 2 is like 40 bucks I think, plus its well documented. Great tools, recommend to any novice asset designer such as myself.

*EDIT - All imgur links now + changed download to dropbox.









Unzip the file, open the folder, and drag all the contents into your bo3 root directory, make sure to restart launcher and run asset convert, then fully build any map you use it in and you're good to go. I spent a shitload of time designing and tweaking these models so maybe a respect or shoutout would be appreciated if you use this, although not necessary. I have many other models like these so if enough of you guys are interested I may release more of them, or perhaps a themed build set.

*I included the two door panels as separate models so you can have them open from the center outwards. Note that I didn't include any prefabs, so you'll have to place the doors as script_models in the map and set it up like any buyable door, just make each door have an opposite script_vector that way they move apart from the center when opened.

**The materials are almost all lit_advanced, so they include diffuse, ambient occlusion, normal, specular, gloss, and one emissive map. Textures are 2048x2048, but the models are relatively low-poly, as best as I could make them. I started modeling less than a year ago so forgive any imperfections.

**Edit - Oops, I just realized in the gdt file I included, I forgot to remove the materials and model for the prototype (earlier) version of this door, please don't look at it lol, looks like playdough. I mean you can use it if you want, but it looks gimpy as hell, lol embarrassing
1137 days ago
This is my first script release, or any release for that matter.

Contained is my custom buildables framework, including a buildable power switch with prefabs for everything, and custom shaders for the parts. To make the shaders (part HUD icons) I simply took a few screenshots of the 3D models in APE, then used photoshop to cut out the part and overlay it on a transparent background, cropped to about 100 X 200 pixels, then set up the materials in APE.

I tried to make this a simple install, so it can be implemented with a few clicks and ctrl+v's. I also extracted sounds from zetsubo to get some nice crafting sounds, building, part pickup, and build complete sounds. I made the "building" logic very fool-proof, meaning there are checks for distance as well as if the player is holding the use button, so if they go out of range of the build-table, or release the use button (plus other checks) then the crafting animation and HUD will cancel instantly. So the player has to remain at the trigger and hold the use button for the entire build process to complete the action or it will reset. I also added in some logic for split-screen players, so the shaders scale in size and position to accommodate.

Instructions:
Download the file and unzip it to your desktop. Drag the contents of the folder named "drag_contents_2root" into you bo3 root directory.

Then move the "custom_buildables_random.gsc" into your mapname\scripts folder.

Open your mapname.gsc in a text editor, navigate to:
function main()
{

Then paste this line at the bottom:
level thread custom_buildables_random::init();
*EDIT: then add this line to your mapname.gsc somehere near the other "#using" lines:
#using scripts\zm\custom_buildables_random;
Next, right-click on your map in launcher, click edit zone file. Add these lines at the bottom:
scriptparsetree,scripts/zm/custom_buildables_random.gsc
xmodel,p7_zm_der_pswitch_body
xmodel,p7_zm_der_pswitch_handle
xmodel,p7_zm_zod_fuse
material,power_panel_shader
material,power_handle_shader
material,power_fuse_shader

Now navigate to your mapname\sound\zoneconfig - and open your mapname.SZC file in a text editor then add these lines:
{
 "Type" : "ALIAS",
 "Name" : "arch_custom_build_sounds",
 "Filename" : "arch_custom_build_sounds.csv",
 "Specs" : [ ]
}

//Add that block of code above the curly and square brackets at the bottom - shown below

]
}

Now in radiant, the prefabs are located in mapsource\_prefabs\archaicvirus_buildables_prefabs. Delete your old power switch first. Drop down the master_power_switch prefab wherever you want the power switch to be. Don't forget that step or it will fail. Then drop down at least 4 of each part's prefab - handle, panel, and fuse. The script will choose a random location to spawn each part, and delete the rest of them each time the map is loaded.  *EDIT: Don't forget to do a full compile\light\link before you test.

When the game starts, the main power panel is hidden. You will see the frame with the chalk lightning bolt on it. This is also the location where you will build the panel. As you pick up each part in-game, it plays a sound, and the default green power-up splash fx. It then draws the part shader on the top-rightish side of all players screen, but only the player who grabbed the part will hear the sound. You can chop up the script all you want to fit your needs. Just study the script and you can see how all the functions are anonymous, meaning you can use them for your own custom buildables. If you need help just let me know. I'm by far an expert but i'll do my best if you want to do something custom.



The video skips a little and vid/sound is a bit out of sync due to my lack of recording experience. In-game though everything is perfect, no lag.

If you use this I would appreciate a shoutout, but I'm not too worried about it either way, just hope it's useful to the modding community in general.

Here is the raw code if you're interested. Note: You need the download + full install for this to work, (includes  sounds, sound alias, custom part shaders, prefabs etc)
#using scripts\codescripts\struct;

#using scripts\shared\array_shared;
#using scripts\shared\callbacks_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\demo_shared;
#using scripts\shared\flag_shared;
#using scripts\shared\hud_util_shared;
#using scripts\shared\laststand_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;

#insert scripts\shared\shared.gsh;
#insert scripts\shared\version.gsh;

#using scripts\zm\_zm_bgb;
#using scripts\zm\_zm_equipment;
#using scripts\zm\_zm_stats;
#using scripts\zm\_zm_unitrigger;
#using scripts\zm\_zm_utility;
#using scripts\zm\_zm_weapons;

#insert scripts\zm\_zm_perks.gsh;
#insert scripts\zm\_zm_utility.gsh;
#insert scripts\zm\craftables\_zm_craftables.gsh;
#precache("model", "p7_zm_der_pswitch_body");
#precache("model", "p7_zm_der_pswitch_handle");
#precache("model", "p7_zm_zod_fuse");
#precache("weapon", "zombie_builder");
#precache( "material", "power_panel_shader");
#precache( "material", "power_handle_shader");
#precache( "material", "power_fuse_shader");
#namespace custom_buildables_random;

  ///////////////////////////////////////
 //         ITITIALIZE FLAGS          //
///////////////////////////////////////
function init(){
level flag::wait_till("all_players_connected");
foreach(player in GetPlayers()){
player.shader_var = [];
}
//wait(3);
//FLAG COMMANDS:
//level flag::init("flagname", false); <-- false so flag is OFF by default, but registered for use in script
//level flag::set("flagname"); <-- turns on "flagname"
//level flag::clear("flagname"); <-- turns off "flagname"
//level flag::get("flagname"); <-- returns true or false if "flagname" is on or off
thread buildable_power();
//thread buildable_e115();
}

  ///////////////////////////////////////
 //         BUIDABLE POWER            //
///////////////////////////////////////
function buildable_power(){
finalflag = "power_crafted";
level flag::init(finalflag, false);
level flag::init("handle_flag", false);
level flag::init("panel_flag", false);
level flag::init("fuse_flag", false);
power_trig = GetEnt("use_elec_switch", "targetname");
power_trig SetCursorHint("HINT_NOICON");
power_trig TriggerEnable(false);
//power_clip = GetEnt("power_clip", "targetname");
//power_clip Hide();
power_panel = GetEnt("main_panel", "targetname");
power_panel Hide();
power_lever = GetEnt("elec_switch", "script_noteworthy");
power_lever Hide();
power_bench = GetEnt("craft_bench", "targetname");
bench_fx_loc = GetEnt(power_bench.target, "targetname");
power_bench.built = false;
power_bench SetCursorHint("HINT_NOICON");
power_bench SetHintString("Missing parts");
fuses = GetEntArray("power_fuse", "script_noteworthy");
handles = GetEntArray("power_handle", "script_noteworthy");
panels = GetEntArray("power_panel", "script_noteworthy");
thread random_spawn(handles, "handle_flag", "p7_zm_der_pswitch_handle", "high-voltage lever");
thread random_spawn(panels, "panel_flag", "p7_zm_der_pswitch_body", "industrial housing");
thread random_spawn(fuses, "fuse_flag", "p7_zm_zod_fuse", "electrical fuse");
power_bench thread build_logic(bench_fx_loc, finalflag, "handle_flag", "panel_flag", "fuse_flag", "electrical panel");
//This function can be copied, and renamed to easily
//create new buildables. Just change the "craft_bench"
//targetname on the bench trigger to "craft_bench_trig_name" etc
//It threads all the stamped prefabs for specified parts
//and deletes all but one. The prefab comes with the model, but you
//first position the prefab wherever you want the part to spawn, then
//you stamp the prefab.
//Lastly -- Threads the random spawn function with the array's of
//each part's possible spawn locations, and the flags to activate when picked up

while(1){
if(level flag::get("power_crafted") == true){
//power_clip Show();
power_panel Show();
power_lever Show();
power_trig TriggerEnable(true);
break;
}else
wait(.1);
}
}

  ///////////////////////////////////////
 //          BUILD LOGIC              //
///////////////////////////////////////
function build_logic(bench_fx_loc, final_flag, part1_flag, part2_flag, part3_flag, build_hint){
while(1){
if(level flag::get(part1_flag) && level flag::get(part2_flag) && level flag::get(part3_flag)){
self SetHintString("Hold &&1 to build "+build_hint);
self waittill("trigger", player);
self SetHintString("");
player PlaySound("build_loop");
PlayFX(level._effect["building_dust"], bench_fx_loc);
player thread crafting_hud(self, final_flag);
player thread custom_craft_anim();
player util::waittill_any("build_canceled", "build_complete");
player StopSound("build_loop");
player StopSounds();
wait(0.1);
if(self.built == true){
player PlaySound("build_done");
foreach(player in GetPlayers()){
player.shader_var1 Destroy();
player.shader_var2 Destroy();
player.shader_var3 Destroy();
}
self Delete();
break;
}
}else
wait(1);
}
}

  ///////////////////////////////////////
 //          RANDOM SPAWN             //
///////////////////////////////////////
function random_spawn(parts, flag, model, hint){
r = RandomInt(parts.size);
foreach(part in parts){
part_model = GetEnt(part.target, "targetname");
if(part == parts[r]){
part thread part_pickup(flag, hint, part_model);
}else{
part_model Delete();
part Delete();
}
}
//Takes in the parts[] array, and flags, you send from your
//buildable function. The parts array is an array of triggers
//left behind from stamping a 'random spawn point' - prefab
//The function then chooses a random trigger to save, and deletes
//the rest of the unused triggers and the script_models they're targeting
//Part pick-up logic is threaded last, right before deleting all
//the spawn locations of the random parts that weren't chosen to spawn
}

  ///////////////////////////////////////
 //        PART PICKUP LOGIC          //
///////////////////////////////////////
function part_pickup(flag, hint, part){
self SetCursorHint("HINT_NOICON");
self SetHintString("Press &&1 to pickup "+hint);
self waittill("trigger", player);
level flag::set(flag);
player PlaySound("part_pickup");
wait(0.1);
PlayFX(level._effect["powerup_grabbed"], self.origin);
foreach(player in GetPlayers()){
switch(self.script_int){
case 1:
if(player IsSplitScreen())
player thread part_shader_logic("power_fuse_shader", 1, 12, 30);
else
player thread part_shader_logic("power_fuse_shader", 1, 24, 60);
break;
case 2:
if(player IsSplitScreen())
player thread part_shader_logic("power_panel_shader", 2, 15, 30);
else
player thread part_shader_logic("power_panel_shader", 2, 31, 60);
break;
case 3:
if(player IsSplitScreen())
player thread part_shader_logic("power_handle_shader", 3, 18, 30);
else
player thread part_shader_logic("power_handle_shader", 3, 35, 60);
break;
}
part Delete();
self Delete();
}
}

  ///////////////////////////////////////
 //         PART SHADER LOGIC         //
///////////////////////////////////////
function part_shader_logic(shader, position, size_x, size_y){
hud = position - 1;
self.shader_var[hud] = NewClientHudElem(self);
self.shader_var[hud].alignX = "right";
self.shader_var[hud].alignY = "top";
self.shader_var[hud].horzAlign = "user_right";
self.shader_var[hud].vertAlign = "user_top";
if(self IsSplitScreen())
self.shader_var[hud].y = ((size_y * position) + 10) - 25;
else
self.shader_var[hud].y = ((size_y * position) + 10);
self.shader_var[hud].x = -5;
self.shader_var[hud] setShader(shader, size_x, size_y);
self waittill("power_crafted");
foreach(shader in self.shader_var){
shader Destroy();
}
}

  ///////////////////////////////////////
 //     CUSTOM CRAFTING ANIMATION     //
///////////////////////////////////////
function custom_craft_anim(){
self endon("disconnect");
self craft_anim_begin();
self util::waittill_any("fake_death", "death", "player_downed", "weapon_change_complete", "build_canceled", "build_complete");
self craft_anim_end();
}

  ///////////////////////////////////////
 //     CRAFTING ANIMATION BEGIN      //
///////////////////////////////////////
function craft_anim_begin(){
self zm_utility::increment_is_drinking();
self zm_utility::disable_player_move_states(true);
primaries = self GetWeaponsListPrimaries();
original_weapon = self GetCurrentWeapon();
weapon = GetWeapon("zombie_builder");
self GiveWeapon(weapon);
self SwitchToWeapon(weapon);
}

  ///////////////////////////////////////
 //      CRAFTING ANIMATION END       //
///////////////////////////////////////
function craft_anim_end(){
self zm_utility::enable_player_move_states();
weapon = GetWeapon("zombie_builder");
if(self laststand::player_is_in_laststand() || IS_TRUE(self.intermission)){
self TakeWeapon(weapon);
return;
}
self zm_utility::decrement_is_drinking();
self TakeWeapon(weapon);
primaries = self GetWeaponsListPrimaries();
if(IS_DRINKING(self.is_drinking)){
return;
}else{
self zm_weapons::switch_back_primary_weapon();
}
}

  ///////////////////////////////////////
 //       CUSTOM CRAFTING HUD         //
///////////////////////////////////////
function crafting_hud(trig, flag){
self.useBar = self hud::createPrimaryProgressBar();
self.useBarText = self hud::createPrimaryProgressBarText();
self.useBarText SetText("Crafting...");
self thread crafting_hud_update(GetTime(), 3000, trig, flag);
}

  ///////////////////////////////////////
 //   CRAFTING HUD UPDATE FUNCTION    //
///////////////////////////////////////
function crafting_hud_update(start_time, craft_time, trig, flag){
self endon("entering_last_stand");
self endon("death");
self endon("disconnect");
self endon("build_canceled");

while(1){
progress = (GetTime() - start_time) / craft_time;
dist = Distance(self.origin, trig.origin);
if(dist > 100 || !self UseButtonPressed() && progress < 1){
self.useBarText hud::destroyElem();
self.useBar hud::destroyElem();
self notify("build_canceled");
break;
}
if(progress < 0){
progress = 0;
}
if(progress > 1 || GetTime() - start_time > craft_time && self UseButtonPressed()){
level flag::set(flag);
foreach(player in GetPlayers()){
player notify(flag);
}
trig.built = true;
self notify("build_complete");
self.useBarText hud::destroyElem();
self.useBar hud::destroyElem();
return trig;
break;
}
if(!self UseButtonPressed() && progress < 1){
self.useBarText hud::destroyElem();
self.useBar hud::destroyElem();
self notify("build_canceled");
break;
}
self.useBar hud::UpdateBar(progress);
WAIT_SERVER_FRAME;
}
}
1163 days ago
I swear I set up everything properly, but when I try to play crafting sounds via script, only one of them plays. This is my setup:

SZC File:
{
 "Name" : "zm_compund",
 "GameMode" : "mpl",
 "IsCommon" : false,
 "Parent" : "",
 "Overlay" : "",
 "IsStandalone" : true,
 "IsProduction" : false,
 "IsShipped" : false,
 "DontDeploy" : false,
 "NoStreamBank" : false,
 "MapFile" : "",
 "Standalone" : true,
 "Builds" : [ "T7" ],
 "Sources" : [
 {
 "Type" : "ALIAS",
 "Name" : "user_aliases",
 "Filename" : "user_aliases.csv",
 "Specs" : [ ]
}
]
}

Zone File:

>class,zm_mod_level
>group,modtools

xmodel,skybox_default_day
material,luts_t7_default

// BSP
col_map,maps/zm/zm_compund.d3dbsp
gfx_map,maps/zm/zm_compund.d3dbsp

// Audio
sound,zm_compund

scriptparsetree,scripts/zm/zm_compund.gsc
scriptparsetree,scripts/zm/zm_compund.csc
scriptparsetree,scripts/zm/e115_collector.gsc
scriptparsetree,scripts/zm/e115_follower.gsc
scriptparsetree,scripts/zm/custom_buildables_random.gsc
xmodel,p7_zm_der_pswitch_body
xmodel,p7_zm_der_pswitch_handle
xmodel,p7_zm_zod_fuse
fx,custom/elec_orb
fx,custom/elec_orb_minion
fx,custom/elec_orb_impact

user_aliases.csv:

Name,Behavior,Storage,FileSpec,FileSpecSustain,FileSpecRelease,Template,Loadspec,Secondary,SustainAlias,ReleaseAlias,Bus,VolumeGroup,DuckGroup,Duck,ReverbSend,CenterSend,VolMin,VolMax,DistMin,DistMaxDry,DistMaxWet,DryMinCurve,DryMaxCurve,WetMinCurve,WetMaxCurve,LimitCount,LimitType,EntityLimitCount,EntityLimitType,PitchMin,PitchMax,PriorityMin,PriorityMax,PriorityThresholdMin,PriorityThresholdMax,AmplitudePriority,PanType,Pan,Futz,Looping,RandomizeType,Probability,StartDelay,EnvelopMin,EnvelopMax,EnvelopPercent,OcclusionLevel,IsBig,DistanceLpf,FluxType,FluxTime,Subtitle,Doppler,ContextType,ContextValue,ContextType1,ContextValue1,ContextType2,ContextValue2,ContextType3,ContextValue3,Timescale,IsMusic,IsCinematic,FadeIn,FadeOut,Pauseable,StopOnEntDeath,Compression,StopOnPlay,DopplerScale,FutzPatch,VoiceLimit,IgnoreMaxDist,NeverPlayTwice,ContinuousPan,FileSource,FileSourceSustain,FileSourceRelease,FileTarget,FileTargetSustain,FileTargetRelease,Platform,Language,OutputDevices,PlatformMask,WiiUMono,StopAlias,DistanceLpfMin,DistanceLpfMax,FacialAnimationName,RestartContextLoops,SilentInCPZ,ContextFailsafe,GPAD,GPADOnly,MuteVoice,MuteMusic,RowSourceFileName,RowSourceShortName,RowSourceLineNumber
zmb_craftable_pickup,,,wpn\craftable.wav,,,UIN_MOD,,,,,,grp_weapon,snp_wpn_1p_shot,,,,99,100,,,,,,,,,,,,,,,,,,,2d,,,NONLOOPING,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
zmb_craftable_buy_shield,,,wpn\craftable.wav,,,GRP_WPN,,,,,,grp_weapon,snp_wpn_1p_shot,,,,75,80,,,,,,,,,,,,,,,,,,,2d,,,NONLOOPING,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
zmb_craftable_complete,,,wpn\zmb_build_completed.wav,,,GRP_WPN,,,,,,grp_weapon,snp_wpn_1p_shot,,,,75,80,,,,,,,,,,,,,,,,,,,2d,,,NONLOOPING,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
zmb_buildable_complete,,,wpn\trial_complete.wav,,,GRP_WPN,,,,,,grp_weapon,snp_wpn_1p_shot,,,,75,80,,,,,,,,,,,,,,,,,,,2d,,,LOOPING,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
zmb_buildable_piece_add,,,wpn\relic_pickup.wav,,,GRP_WPN,,,,,,grp_weapon,snp_wpn_1p_shot,,,,75,80,,,,,,,,,,,,,,,,,,,2d,,,NONLOOPING,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
zmb_craftable_loop,,,wpn\zmb_building_lp.wav,,,GRP_WPN,,,,,,grp_weapon,snp_wpn_1p_shot,,,,75,80,,,,,,,,,,,,,,,,,,,2d,,,LOOPING,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
zmb_craftable_buy_shield,,,wpn\craftable.wav,,,GRP_WPN,,,,,,grp_weapon,snp_wpn_1p_shot,,,,75,80,,,,,,,,,,,,,,,,,,,2d,,,NONLOOPING,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

Script where I'm calling PlaySound()

  ///////////////////////////////////////
 //          BUILD LOGIC              //
///////////////////////////////////////
function build_logic(bench_fx_loc, final_flag, part1_flag, part2_flag, part3_flag, build_hint){
while(1){
if(level flag::get(part1_flag) && level flag::get(part2_flag) && level flag::get(part3_flag)){
self SetHintString("Hold &&1 to build "+build_hint);
self waittill("trigger", player);
self SetHintString("");
player PlaySound("zmb_craftable_loop");
PlayFX(level._effect["building_dust"], bench_fx_loc);
player thread crafting_hud(self, final_flag);
player thread custom_craft_anim();
player util::waittill_any("build_canceled", "build_completed");
player StopSounds();
if(self.built == true){
player PlaySound("zmb_craftable_complete");
self Delete();
break;
}
}else
wait(1);
}
}

It only plays the "zmb_craftable_complete" sound, but it won't play the building loop sound, and it won't play the 'pickup' sound as shown below

  ///////////////////////////////////////
 //        PART PICKUP LOGIC          //
///////////////////////////////////////
function part_pickup(flag, hint, part){
self SetCursorHint("HINT_NOICON");
self SetHintString("Press &&1 to pickup "+hint);
self waittill("trigger", player);
level flag::set(flag);
player PlaySound("zmb_buildable_piece_add");
wait(0.1);
PlayFX(level._effect["powerup_grabbed"], self.origin);
part Delete();
self Delete();
}

Am I missing something?  I checked in root/sound_assets, and all the .WAV files are there, and in the correct folders. I even opened the files in audacity, and they're all set to 48000 which is correct. I even tried re-converting them in audacity and renamed them and same thing, only the one sound plays. It doesn't make sense.
1171 days ago
Does anyone know the proper method to set up fx via script? I used ugx easyfx for codwaw, and understand that fx need to be precached whether they are custom or stock.

The problem I'm having is that I've tried to precache an existing effect - electric\fx_elec_sparks_bounce_blue and launcher won't load the map. This is the final error output through the launcher console -
^1
^1^
^1ERR(6E) scripts/zm/zm_montys_lab.gsc (87,0)  : Compiler Internal Error :  Unresolved external 'zm_weapons::load_weapon_spec_fr0m_table'

 I have a very simple function to test adding in fx, for controlling via scripting. It's a snippet from a codwaw project I was working on.

#define E115_FX			"electric\fx_elec_sparks_bounce_blue"
#precache( "fx", E115_FX );

function e115_init(){
level flag::wait_till( "all_players_connected" );
elec_orb = Spawn("script_model",player.origin);
elec_orb SetModel("tag_origin");
PlayFXOnTag(E115_FX, elec_orb, "tag_origin");
level thread e115_update();
}

function e115_update(){
while(1){
f = anglesToForward(player.angles)*50;
r = anglesToRight(player.angles)*30+f;
r += (0,0,60);
elec_orb MoveTo(player.origin + r, .1, .0, 0);
wait(0.5);
}
}


I've tried precaching in the right places from what I can remember, but I can't get it work. I've looked for a topic on this issue for BO3 and can't find any clear tutorials. Any help would be appreciated.  This is my mapname.gsc -
#using scripts\codescripts\struct;

#using scripts\shared\array_shared;
#using scripts\shared\callbacks_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\compass;
#using scripts\shared\exploder_shared;
#using scripts\shared\flag_shared;
#using scripts\shared\laststand_shared;
#using scripts\shared\math_shared;
#using scripts\shared\scene_shared;
#using scripts\shared\util_shared;

#insert scripts\shared\shared.gsh;
#insert scripts\shared\version.gsh;

#insert scripts\zm\_zm_utility.gsh;

#using scripts\zm\_load;
#using scripts\zm\_zm;
#using scripts\zm\_zm_audio;
#using scripts\zm\_zm_powerups;
#using scripts\zm\_zm_utility;
#using scripts\zm\_zm_weapons;
#using scripts\zm\_zm_zonemgr;
//#using scripts\zm\_zm_blockers;

#using scripts\shared\ai\zombie_utility;

//Perks
#using scripts\zm\_zm_pack_a_punch;
#using scripts\zm\_zm_pack_a_punch_util;
#using scripts\zm\_zm_perk_additionalprimaryweapon;
#using scripts\zm\_zm_perk_doubletap2;
#using scripts\zm\_zm_perk_deadshot;
#using scripts\zm\_zm_perk_juggernaut;
#using scripts\zm\_zm_perk_quick_revive;
#using scripts\zm\_zm_perk_sleight_of_hand;
#using scripts\zm\_zm_perk_staminup;

//Powerups
#using scripts\zm\_zm_powerup_double_points;
#using scripts\zm\_zm_powerup_carpenter;
#using scripts\zm\_zm_powerup_fire_sale;
#using scripts\zm\_zm_powerup_free_perk;
#using scripts\zm\_zm_powerup_full_ammo;
#using scripts\zm\_zm_powerup_insta_kill;
#using scripts\zm\_zm_powerup_nuke;
#using scripts\zm\montys_test;
//#using scripts\zm\_zm_powerup_weapon_minigun;

//Traps
#using scripts\zm\_zm_trap_electric;

#using scripts\zm\zm_usermap;

//*****************************************************************************
// MAIN
//*****************************************************************************

function main()
{
zm_usermap::main();
level thread e115_init();
level._zombie_custom_add_weapons =&custom_add_weapons;

//Setup the levels Zombie Zone Volumes
level.zones = [];
level.zone_manager_init_func =&usermap_test_zone_init;
init_zones[0] = "start_zone";
level thread zm_zonemgr::manage_zones( init_zones );

level.pathdist_type = PATHDIST_ORIGINAL;
}

function usermap_test_zone_init()
{
zm_zonemgr::add_adjacent_zone("start_zone","zone2","enter_zone2");

level flag::init( "always_on" );
level flag::set( "always_on" );
}

function custom_add_weapons()
{
zm_weapons::load_weapon_spec_fr0m_table("gamedata/weapons/zm/zm_levelcommon_weapons.csv", 1);
}

And my zone file -
>class,zm_mod_level
>group,modtools

xmodel,skybox_default_day
material,luts_t7_default
fx,electric\fx_elec_sparks_bounce_blue //<----------------
// BSP
col_map,maps/zm/zm_montys_lab.d3dbsp
gfx_map,maps/zm/zm_montys_lab.d3dbsp

// Audio
sound,zm_montys_lab

scriptparsetree,scripts/zm/zm_montys_lab.gsc
scriptparsetree,scripts/zm/zm_montys_lab.csc
1198 days ago
What I'm trying to do is is a moveto on an entity, which I can do easily, but the problem I'm having is figuring out how to keep the entity in front of the player at all times. For example:
little_shoulder_devil()
{
x = ("50"); // 50 units in front of players face
y = ("50"); // 50 units to the right of player
z = ("50"); // 50 units above players shoulder
}

guardian_follow()
{
while(flag(var))
{
if(life <= 0)
{
ent moveto(player.origin+(x,y,z));
wait .05;
}
else
{
thread cooldown();
break;
}
}
}
(


This is not my exact code but a mockup of what I'm trying to do. I noticed the geteye() function in the ugx script references, but to my understanding that gets the angles of the player's facing direction. This is where my problem is, I can't figure out how to adjust the moveto coordinates relative to the player's facing angle. For example, if north is +x, and south is -x, and so on for y and z, how can I convert the facing direction to a relative offset of the player. If anyone could give me some suggestions I would greatly appreciate it, as well as give you credit in a mutual project I'm working on. Hopefully I explained my intentions clearly, if not let me know and I'll elaborate.
1392 days ago

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
Loading ...