Birds fly. Sun shines. And brother? Brutes shoot people.

UScript: Chat, Questions, Discussion

For questions and discussion about UnrealEd, UnrealScript, and other aspects of Unreal Engine design.

Moderators: ividyon, Semfry, zYnthetic

User avatar Buff Skeleton
>:E >:E
Posts: 4045
Joined: 15 Dec 2007, 00:46

Subject: UScript: Chat, Questions, Discussion

Post Posted: 09 Jan 2012, 14:57

I know there's a handy number of people here who understand scripting, so I thought we could use a thread dedicated to it and help each other out with our problems. Or just rant about the lack of native dynamic arrays or whatever.

I'll reserve this post for more links and stuff if in the future it takes off. For now, though:

Posting Guidelines

  1. If you post A LOT of code, don't use the [code] tags. Use Pastebin.com or some other external host and link it. If you have to post a lot of code, at least wrap it in [spoiler] tags so it doesn't stretch the thread out too much!
    _
  2. Make sure you identify what platform you're working with. There's different things going on between Unreal and UT and 227 and UT2k4+, etc.
    _
  3. Don't ignore the Unreal Wiki! A lot of basic questions can be answered by looking at the references here, but don't be afraid to ask what you might consider a dumb question if you aren't sure how to interpret something.
    _
  4. Please try to keep your code legible. Be consistent with your indentation, however you do it. If you don't indent well, now would be a good time to start. It makes understanding your code a LOT easier. Help us help you, etc.
_

I figure that's a good start for guidelines. Now for the chat!
Image

User avatar Buff Skeleton
>:E >:E
Posts: 4045
Joined: 15 Dec 2007, 00:46

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 09 Jan 2012, 15:47

I have a Brute problem.

For EXU, I've rewritten all of the fire offsets for pawns, using a Location + (vect(x,y,z) * DrawScale>>Rotation) system instead of the collision-cylinder-based fire offset seen in ScriptedPawn.FireProjectile(). I do this so I can have more accurate fire offsets based on the pawn's animations, more flexible projectile accuracy controls, custom muzzle flashes, etc. This also prevents weird offsets if the collision cylinder is bigger than normal. It looks pretty good ingame and is working fine for most pawns, but Brutes have a problem: they can shoot through walls and doors in some cases.

Image

Location 1: This is the current, new fire offset for spawning the left shot in StillFire mode: vect( 134, -29, 30 )
Location 2: This is the original, collision-based fire offset (calculated to the actual location), used for all instances of SpawnLeftShot: vect( 62.4, -36.4, 20.8 )
Location 3: This is the CanFireAtEnemy offset used for tracing. It was also collision-based, but I am now using an actual offset calculated from the original formula: vect( 26, -42, 20.8 )


THE PROBLEM:
As you can see, the fire offset is pretty far ahead of the collision cylinder by default, but it was also somewhat ahead even in Unreal based on the original offset. However, if a Brute is partially obscured by a thin wall or a door, it can fire "through" the door since the fire offset will be on one side while the collision cylinder will be on the other. Is there a way to rectify this?

I've considered doing a trace or a fasttrace in CanFireAtEnemey from Location 3 to Location 1 to verify that the pawn should be able to shoot, but don't know if this would be overly expensive in terms of performance. I really would like to keep the fire offsets where they visually should be, as the muzzle flashes look good spawned there. But if nothing else works, I can always make the muzzle flashes spawn at Location 1 and have the projectiles spawn at Location 2.


Here's the original Brute fire functions, for reference:
[spoiler]

Code: Select all

//=======================================================
function SpawnLeftShot()
{
   FireProjectile( vect(1.2,0.7,0.4), 750);
}

function SpawnRightShot()
{
   FireProjectile( vect(1.2,-0.7,0.4), 750);
}

function GutShotTarget()
{
   FireProjectile( vect(1.2,-0.55,0.0), 800);
}
//=======================================================
[/spoiler]

And here's the original ScriptedPawn.FireProjectile function for reference:
[spoiler]

Code: Select all

//=======================================================
final function FireProjectile(vector StartOffset, float Accuracy)
{
   local vector X,Y,Z, projStart;

   MakeNoise(1.0);
   GetAxes(Rotation,X,Y,Z);
   projStart = Location + StartOffset.X * CollisionRadius * X + StartOffset.Y * CollisionRadius * Y + StartOffset.Z * CollisionRadius * Z;
   spawn(RangedProjectile ,self,'',projStart,AdjustAim(ProjectileSpeed, projStart, Accuracy, bLeadTarget, bWarnTarget));
}
//=======================================================
[/spoiler]

Also: the CanFireAtEnemy function for the Brute. Commented is the original collision-based calculation, and the current code uses the actual position times drawscale (note that I removed some local vars that weren't needed with the actual offsets in use instead of getting the offset from collision):
[spoiler]

Code: Select all

//=======================================================
function bool CanFireAtEnemy()
{
   local vector HitLocation, HitNormal, projStart, EnemyDir, EnemyUp;
   local actor HitActor1, HitActor2;
   local float EnemyDist;
      
   EnemyDir = Enemy.Location - Location;
   EnemyDist = VSize(EnemyDir);
   EnemyUp = Enemy.CollisionHeight * vect(0,0,0.9);
   if ( EnemyDist > 300 )
   {
      EnemyDir = 300 * EnemyDir/EnemyDist;
      EnemyUp = 300 * EnemyUp/EnemyDist;
   }

   projStart = Location + ( vect(26, 41.6, 20.8) * DrawScale>>Rotation );            // Right Shot
   HitActor1 = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true);

   if ( (HitActor1!=Enemy) && (Pawn(HitActor1)!=None) && (AttitudeTo(Pawn(HitActor1)) > ATTITUDE_Ignore) )
      return false;

      
   projStart = Location + ( vect(26, -41.6, 20.8) * DrawScale>>Rotation );            // Left Shot
   HitActor2 = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true);

   if ( (HitActor2 == None) || (HitActor2 == Enemy) || ((Pawn(HitActor2) != None) && (AttitudeTo(Pawn(HitActor2)) <= ATTITUDE_Ignore)) )
      return true;

   HitActor2 = Trace(HitLocation, HitNormal, projStart + EnemyDir, projStart , true);

   return ( (HitActor2 == None) || (HitActor2 == Enemy) || ((Pawn(HitActor2) != None) && (AttitudeTo(Pawn(HitActor2)) <= ATTITUDE_Ignore)) );


/*
   GetAxes(Rotation,X,Y,Z);
   projStart = Location + 0.5 * CollisionRadius * X + 0.8 * CollisionRadius * Y + 0.4 * CollisionRadius * Z;
   HitActor1 = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true);
   if ( (HitActor1 != Enemy) && (Pawn(HitActor1)!=None) && (AttitudeTo(Pawn(HitActor1)) > ATTITUDE_Ignore) )
      return false;
      
   projStart = Location + 0.5 * CollisionRadius * X - 0.8 * CollisionRadius * Y + 0.4 * CollisionRadius * Z;
   HitActor2 = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true);

   if ( (HitActor2 == None) || (HitActor2 == Enemy) || ((Pawn(HitActor2) != None) && (AttitudeTo(Pawn(HitActor2)) <= ATTITUDE_Ignore)) )
      return true;

   HitActor2 = Trace(HitLocation, HitNormal, projStart + EnemyDir, projStart , true);

   return ( (HitActor2 == None) || (HitActor2 == Enemy) || ((Pawn(HitActor2) != None) && (AttitudeTo(Pawn(HitActor2)) <= ATTITUDE_Ignore)) );
*/
}
//=======================================================
[/spoiler]
Image

User avatar []KAOS[]Casey
Skaarj Berserker Skaarj Berserker
Posts: 425
Joined: 25 Sep 2008, 07:25

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 09 Jan 2012, 21:10

Use a FastTrace from point 3 to 1. There is a reason why it's called fast trace. :P

what strikes me odd though is the CanFireAtEnemy should stop this if it actually is indeed point 3.

Needs moar logs.

User avatar Buff Skeleton
>:E >:E
Posts: 4045
Joined: 15 Dec 2007, 00:46

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 09 Jan 2012, 21:49

Yeah, I'll get some logs when I get a chance.

I think CanFireAtEnemey, in the Brute's case (as well as the Skaarj's) will pass if EITHER fire offset is able to hit, since it fires from two places. So if the Brute's right arm can hit you but the left can't, the right side will pass and it will try to hit you with the right... in theory. I've seen Brutes firing with ONLY the left when the right could clearly pass and the left (visually) could not, which is double-weird.
Image

redeye
Banned Banned
Posts: 1393
Joined: 08 Dec 2007, 06:55

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 11 Jan 2012, 21:03

Someone go fix the "artifacts" for unreal2, the code is there but all green text and REM'ed.Or make me a pickup for faster running speed.I would like to know if they even had any effect for the game at all, even if they where just to be collected.
Just ban everyone

User avatar ebd
Trustee Member Trustee Member
Posts: 428
Joined: 05 Apr 2008, 19:08
Contact:

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 19 Jan 2012, 08:18

The Log wrote:Warning: Can't save ..\Save\Save6.usa: Graph is linked to external private object Package Transient
When is an object implicitly transient? Ideally these references (and the objects they reference) would be written to disk on save. I've searched but can't seem to find any functions that get called when an object is saved or loaded, which would be a decent alternative solution (to recreate the data that couldn't be saved).

Here is the (abridged) code that is the source of the transient references:
[spoiler]

Code: Select all

class JournalEvent extends Triggers;

#exec TEXTURE IMPORT NAME=i_JournalEvent FILE=Textures\oll_icon_journalevent.pcx GROUP="Icons" MIPS=OFF FLAGS=2

struct JournalEventEntry {
  var() localized String entryName;
  var() bool indent;
  var() localized String entryText;
};

//most vars omitted
var() JournalEventEntry entriesByState[10];
var JournalListEntry entries[10]; //these are transient (apparantly!)

function postBeginPlay() {
  local byte i;
  local JournalListEntry jle;
  for (i = 0; i < 10; i++) {
    if (entriesByState[i].entryText != "") {
      jle = new (none) class'JournalListEntry';
      jle.entryName = entriesByState[i].entryName;
      jle.indent = entriesByState[i].indent;
      jle.entryText = entriesByState[i].entryText;
      entries[i] = jle;
    }
  }
}

//code goes on...
[/spoiler]

And the JournalListEntry class:
[spoiler]

Code: Select all

class JournalListEntry extends JournalData;

var() localized String entryName;
var() bool indent;
var() localized String entryText;
[/spoiler]

So I suspect I shot myself in the foot by creating the objects during postBeginPlay(), or that maybe it has something to do with non-actor classes. The idea was for it not to be a total pain when using this actor within a level by setting the properties into structs while editing and having the data wrapped up when the level starts. The (sucky) alternative is to have all the data that would have been in each instance's properties be stored as literals somewhere else with class references (or an index, or something) in its place. This might actually make localization easier, but please forgive me when I say that ease of localization is not high on my priority list for a project which was I intended to be done with six months ago.

User avatar []KAOS[]Casey
Skaarj Berserker Skaarj Berserker
Posts: 425
Joined: 25 Sep 2008, 07:25

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 19 Jan 2012, 08:29

What's a "JournalData"? Is it an object? Properties?

Besides, I think this is your problem.

Code: Select all

new (none) class'JournalListEntry';


you can't save a NULL package. Easiest fix I can think of is..

Code: Select all

var transient JournalListEntry entries[10];


But then again postbeginplay may not be called again and it would FUBAR. You should add some checks in postbeginplay to make sure the Entries are null before creating them.

Try

Code: Select all

new (Outer) class'JournalListEntry';



Oh and, since you're dealing with Objects.. at least I think you are.. be very careful what references them. Objects don't clean up like Actors do for whatever reason.

Add this to your Trigger.

Code: Select all

function Destroyed()
{
   local int i;
   for(i=0; i<ArrayCount(Entries); i++)
   {
      /*if(Entries[i] != None)
         Entries[i].Var = None;// if the Entry has any reference to any actor, null it.
      */
      Entries[i] = None; //null object reference
   }
}

User avatar ebd
Trustee Member Trustee Member
Posts: 428
Joined: 05 Apr 2008, 19:08
Contact:

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 19 Jan 2012, 10:26

I should have mentioned JournalData extends Object, has no properties and only serves to keep the hierarchy from being too cluttered with linked list classes and list entries (really it is padding the file size with a few extra bytes).
[]KAOS[]Casey wrote:...Try new (Outer) class'JournalListEntry';
This worked great! All the documentation I've seen on non-actor instantiation was a little lacking on that crucial part, and I could really find anything that described what happens when you save. I'm familiar with the definition of transient in Java, but of course Java also has methods that are called when an object is serialized to allow programmers to store transient data some other way, or recreate it later.
[]KAOS[]Casey wrote:But then again postbeginplay may not be called again and it would FUBAR.
All of my testing pointed to this.

Also just judging by the object names in my logs, objects seem to be garbage collected when a different level is loaded, but if the same level is restarted they are not garbage collected. Even setting destroyed() functions to carefully disassemble linked lists setting all the references within to none seems to have no affect on this.

User avatar []KAOS[]Casey
Skaarj Berserker Skaarj Berserker
Posts: 425
Joined: 25 Sep 2008, 07:25

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 19 Jan 2012, 21:46

Glad it worked.

I'm sure the lack of documentation is because most mods are created to work in the multiplayer gamestate where saving isn't very important.

Z-enzyme
White Tusk White Tusk
Posts: 2135
Joined: 13 Nov 2007, 20:01

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 22 Jan 2012, 19:58

A chart I came across some time ago...

I just thought it might be useful for someone.

User avatar []KAOS[]Casey
Skaarj Berserker Skaarj Berserker
Posts: 425
Joined: 25 Sep 2008, 07:25

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 22 Jan 2012, 20:48

Hey, it even points out the BS inconsistency between Left and Right. Compile and debug section is wrong, but it probably wasn't made for UE1.

I give it an 95/100

Whoops! It doesn't point out perobjectconfig or globalconfig... OR localized. 90/100.

Z-enzyme
White Tusk White Tusk
Posts: 2135
Joined: 13 Nov 2007, 20:01

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 22 Jan 2012, 22:55

May you correct it then?

User avatar []KAOS[]Casey
Skaarj Berserker Skaarj Berserker
Posts: 425
Joined: 25 Sep 2008, 07:25

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 23 Jan 2012, 09:35

Really, the only one worth mentioning that's missing is localized. globalconfig is sorta useless unless you want to inherit properties from parent class, and perobjectconfig needs a couple paragraphs of explanation of proper use. The only reason i've ever used that is to go past the ini storage limitations but even then it was a lot of data.. too much, which is why I made the SQL interface native mod.

User avatar Buff Skeleton
>:E >:E
Posts: 4045
Joined: 15 Dec 2007, 00:46

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 23 Jan 2012, 17:08

[]KAOS[]Casey wrote:Use a FastTrace from point 3 to 1. There is a reason why it's called fast trace. :P

what strikes me odd though is the CanFireAtEnemy should stop this if it actually is indeed point 3.

Needs moar logs.


Finally got around to investigating this some more yesterday. Oddly enough, CanFireAtEnemy is never called, apparently. I had all sorts of logs in there and even a fasttrace from Point 3 to Point 1 (for both sides) and never saw any of them. Only when I called CanFireAtEnemy manually in each individual shooting function did it start to work, but that's obviously inelegant and doesn't stop the pawn from playing the fire anim even if no projectiles are spawned.

I'm going to dig through the Brute code some more to see if CanFireAtEnemy is ever supposed to be called, and if it is, figure out why it isn't. Failing that, if I can't fix the source of the problem, I'm going to probably rewrite the entire Brute firing system from scratch and get rid of the anim notify functions, opting instead to use fire states with configurable delays (so it works like the anim notify system without actually using it; I did a similar thing for EXUTitan that worked out pretty well).

Fun times ahead!
Image

Nelsona
Skaarj Scout Skaarj Scout
Posts: 12
Joined: 22 May 2011, 14:23

Subject: Re: UScript: Chat, Questions, Discussion

Post Posted: 22 Mar 2012, 23:15

Switched here at Waffnuffly suggestion from EXU thread related to coding-modding.

I saw other technology to enhance monsters in EXU2 more exactly nightmare mutator meant to bring some difficulty (I guess :D). Another default ideea for games with monsters like MH has a function to increase pawn's power and other things (called SetPawnDifficulty right in controller and called later in BaseMutator in AlwaysKeep targeting 2 things: presence of certain monsters missing and keep the power of monsters). Except speed, hearing, combat style, I didn't saw anywhere something like Monster.Skill called. Anyway this kind of code I think is stressfull for game since AlwaysKeep is powerfull and is checking even 500 monsters at once as I can notice from codes. I want to do another kind of MH breaking all default codes, I want to deliver a better speed, even giving up using that so called Lives configuration because is useless (in my opinion). You had a different way to deal with monsters (you called a SpawnNotify subclass). Is faster or better ? I want to try that style. That original MH function was also defined to check that so called skilled monster versus non-skilled using a shadow non-replicated, existing only in server or local games, LOL. Your function for boosting monsters have another kind of functionality. How is acting ? I just want to test it removing that original high loaded and using yours ideea. Of course I have other questions related to shadow decal, can slow down worse the server or not ? Maybe you can suggest some tricks that need to be tested.

Next

Who is online

Users browsing this forum: No registered users and 2 guests