Activating entities Created 8 years ago2016-09-26 10:56:19 UTC by abbadon abbadon

Created 8 years ago2016-09-26 10:56:19 UTC by abbadon abbadon

Posted 8 years ago2016-09-26 15:06:35 UTC Post #331766
Hi. As a relax between hard modelling sessions I am doing some experiments (thanks Solokiller!! :P )with the monstermaker entity, but with little or no luck.

My troubles come when I try to activate them using a command (reload button) instead of using a func_button or a multimanager or a trigger entity. If I try to do so, game exits to console, but it not crashes. The code compiled fine btw.

I always used a serie of trigger_auto and buttons to activate monstermakers, but, after testing the use of commands, must they only be activated by those entities (button, triggers, multimanager)?

Edit: the game now does not exit to console but pressing the reload button does nothing...
Posted 8 years ago2016-09-27 08:18:45 UTC Post #331771
"Talk is cheap, show me the code" - Linus Torvalds.
Posted 8 years ago2016-09-27 13:52:47 UTC Post #331774
As you wish, my lord... This is the code that I managed to make with the aid and advices of Solokiller, of course every and each mistake here is mine, not him´s, I must left this crystal clear ;)

In twohand.cpp
_____________

[quote]void CTwohand::Reload( void )
{
//============================================================
// Inicio las pruebas del codigo para el modo RECARGA el 25 de Septiembre de 2016
//============================================================
// If playe/weapon has les than 100 bullets, let it reload.
if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] || m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] <= 100)
{
    	CBaseEntity *pEntity = NULL;

	while ((pEntity = UTIL_FindEntityInSphere( pEntity, m_pPlayer->pev->origin, 10000 )) != NULL)
	{
		if (FClassnameIs( pEntity->pev, "monstermaker"))
		{
				pEntity->Use( pEntity, pEntity, USE_ON, 0 );// Doubts here.
				m_flNextReload = UTIL_WeaponTimeBase() + 60;
				m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5;
	   	 }
	}
}

//If player have enough ammo don¥t let him reload.
if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] || m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] >= 100)
	return;

// Check to see if we're ready to reload!!Also, if player has 600 ammo play reload animation.

if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] || m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] >= 600)
{
	SendWeaponAnim( TWOHAND_RELOAD );
	return;
}
}
[/quote]

In Weapons.cpp
____________

[quote]
TYPEDESCRIPTION CTwohand::m_SaveData[] =
{
DEFINE_FIELD( CTwohand, m_flNextReload, FIELD_TIME ),
};
IMPLEMENT_SAVERESTORE( CTwohand, CBasePlayerWeapon );
[/quote]

In weapons.h
___________
[quote]
#ifndef CLIENT_DLL
int		Save( CSave &save );
int		Restore( CRestore &restore );
static	TYPEDESCRIPTION m_SaveData[];
#endif
float m_flNextReload;
[/quote]

Also, in my last tests I have added alerts in every part of the code that makes the monster and also in the main reload part, but, with no luck at all... In fact, I feel quite surprised that no messages appear in the console, I use the "ALERT ( at_console, "yourtexthere\n" );" thingy in every place where a "return;" appeared like gently Solokiller point me to do.

Most probably the code above is just a bunch of useless lines of bad and misplaced code, the one I have used , overall the code inside the void CTwohand::Reload( void ) function, It was just taken from the satchel.cpp file. The last try I have made is this :

[quote]

edict_t *pPlayer = m_pPlayer->edict( );
CBaseEntity *pEntity = NULL;
while ((pEntity = UTIL_FindEntityInSphere( pEntityl, m_pPlayer->pev->origin, 10000 )) != NULL)
	{
		if (FClassnameIs( pEntity->pev, "monstermaker"))
		{
				pEntity->Use( m_pPlayer, pEntity, USE_ON, 0 );
		}
	}
[/quote]

This last part pEntity->Use( m_pPlayer, pEntity, USE_ON, 0 ); I wrote it by memory, because I don´t have the code visible (the rest of the code above Is from a backup txt). Again, no luck and no visible effect at all. monstermakers, btw, worked as usual. The one I used to made the tests have its flag "targetname" with the name "sentinel" and also without any name, and with the flag "cyclic" activated and desactivated ( targetname on + cyclic on, targetname off +cyclic on, targetname off+cyclic off, targetname on+ cyclic off).

Qc file is Ok, and the model shows the reload animation in the model viewer, but, as it uses no clips, it is overriden by the reload code itself (no clips, no animation is displayed)..

The reload function (client and server) is the original, with no added parts.

Of course I made a full recompile of both client and serverl dlls.

I hope I satisfied your curiosity ;) :P
Posted 8 years ago2016-09-27 15:11:47 UTC Post #331776
First mistake: you are performing the "check if weapon is loaded/empty" code twice.

Second mistake: your check is incorrect, this:
if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] || m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] <= 100)
Means: IF primary ammo is something else than 0 OR secondary ammo <= 100.

Third: I don't understand why you use the primary/secondary ammo in reload. Unless you are making the weapon like the ones in Overwatch (infinite ammo but reload).

Fourth: Study this little example, adapt it to your needs:
void CTwohand::Reload( void )
{
// Don't reload if primary OR secondary ammo is equal or above 100
if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= 100 || m_pPlayer->m_rgAmmo[m_iSecondaryAttack] >= 100 )
return;

// The code below is executed if you have less than 100 primary AND secondary ammo, no need to do another if/else
CBaseEntity *pEntity = NULL;
// The "start entity" should be the player, not something else
while ((pEntity = UTIL_FindEntityInSphere( m_pPlayer, m_pPlayer->pev->origin, 10000.0f ) != NULL)
{
if ( FClassnameIs( pEntity->pev, "monstermaker" ) )
pEntity->Use( m_pPlayer, m_pPlayer, USE_ON, 0.0f ); // You specified the entity itself as the "caller" which is wrong, the player should be the activator AND the caller.
}
}
EDIT : Don't call me a lord just because I posted a quote from Linux's father, the idea behind this quote (I think you've found out already) is that when you have an issue with your code, the code itself is more appropriate to help rather than an explanation, it's like making a presentation with PowerPoint/Impress full of text with no images at all ^^
Posted 8 years ago2016-09-27 15:46:00 UTC Post #331777
oh!, I'm sorry :( I don't pretend to offend, I swear!!, I have just kidding a bit, but, I must admit that you coders are for me like lords!! ;)

See what I told to you?, the code was all wrong!!, I have made changes here and there using what I know, pity is that trial error is not a good method to code. :(

I will try your code tonight and post the results.

Thank you Sheppard!! ^^
Posted 8 years ago2016-09-27 19:25:46 UTC Post #331778
Tested!!... but with no luck. Code compiled fine, and I have added also an ALERT so each time I press "+reload" button (R) the message "CALLING RELOAD TEAM!!" is displayed on screen. But neither the monstermaker work nor the message appeared. It is like if the reload does not work in my MOD!!, should it be caused by this code in weapons.cpp?

In CBasePlayerWeapon::ItemPostFrame

[blue][quote] else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload )
{
	// reload when reload is pressed, or if no buttons are down and weapon is empty.
	Reload();
}[/quote][/blue]
Or...


[blue][quote]// weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) )
		{
			Reload();
			return;
		}
	}
	WeaponIdle( );
	return;
}[/quote][/blue]
I repeat that it looks like the reload button does not work at all, at least it should appear the ALERT message even if code does not work!.

Here is where the RELOAD appear in weapons.cpp, and it seems to be related to weapons that use clips, could be my weapons because of not having clips nor magazines be culprit of the code do not work?.

I am now lost as hell...
Posted 8 years ago2016-09-27 19:26:15 UTC Post #331779
Remove the iMaxClip() != WEAPON_NOCLIP on ItemPostFrame, I had that issue with Para's sabre
Posted 8 years ago2016-09-27 20:11:48 UTC Post #331780
Ok Shepard, I will test it tomorrow. If it works I will also test the TeamName check. Thanks Shepard!! ^^
Posted 8 years ago2016-09-28 15:10:43 UTC Post #331783
Success!! :) ... almost :(

The reload button now works fine. ;)
User posted image
...but the monstermakers still did not work (remember that I use 4 types with targetname and "cyclic" tab activaded and deactivated).

The code is now like this (if you tell me that it is still wrong I will believe it)... :|

NOTE: I have commented the m_pPlayer->m_rgAmmo conditioner to use the RELOAD button as I start the map.

[quote]
void CTwohand::Reload( void )
{
{ 
//if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= 100 || m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] >= 100 )
//	return;

CBaseEntity *pEntity = NULL;
while ((pEntity = UTIL_FindEntityInSphere( m_pPlayer, m_pPlayer->pev->origin, 10000.0f )) != NULL)
{
	if ( FClassnameIs( pEntity->pev, "monstermaker" ) )
pEntity->Use( m_pPlayer, m_pPlayer, USE_ON, 0.0f );

	}
	ALERT( at_console, "RELOAD!!\n" );
}
}[/quote]

I know we are almost there!!. It is not much code to do for the mod, I want to add two new features (very simple), and this one is definitive!!.

NOTE: remember, if this works it will be Sheppard and Solokiller´s victory, not mine in any manner!! ("give to Caesar what is Caesar´s").

XP
Posted 8 years ago2016-09-28 18:30:16 UTC Post #331788
Try printing out the classname of every entity it finds. It'll spam the console, but at least you can see what it finds. If monstermakers aren't in the list, then it isn't finding them. The most likely cause would be that they're too far away, so increasing the radius would help.
Posted 8 years ago2016-09-28 18:46:28 UTC Post #331790
How do I do it? :/ I mean, printing out the classname of every entity.

I put a radius of 30000 and also used the reload button almost on top of the monstermaker entity. But I will try bigger numbers. ;)
Posted 8 years ago2016-09-28 19:14:45 UTC Post #331791
ALERT( at_console, "Classname: %s\n", STRING( pEntity->pev->classname ) ); should do it.
Posted 8 years ago2016-09-28 19:39:22 UTC Post #331792
Done!, with extrange results...

If I put that code inside the:
CBaseEntity *pEntity = NULL;
while ((pEntity...etc,etc.
part, notting happened.

But if I put it outside (following the last "}" ), the game crashes forcing me to use ctrl+alt+supr.

It is like if that code, the "while ((pEntity..." does not work. :/
Posted 8 years ago2016-09-28 19:42:40 UTC Post #331793
Well, i see one thing that's wrong with it: you're passing the player as the start entity for the search. You should be passing in pEntity.

Also, are you sure this is running on the server side? I'm not seeing any #ifdefs to exclude it from the client side.
Posted 8 years ago2016-09-28 20:14:44 UTC Post #331794
If I put #ifdef in the function the reload button does not work :| ...

Also, If I add...

edict_t *pPlayer = m_pPlayer->edict( );

because I saw it in the satchel.cpp located in the same function frow where I have extracted the "while" code, the reload button does not work either, or it is like if the code does not go further the edict_t part O_o

Also, If I use pEntity in while ((pEntity = UTIL_FindEntityInSphere( m_pPlayer, m_pPlayer->pev->origin, 500000.0f)) !=NULL), notting happens.

I am testing all this starting the map from the console, not by starting a new multiplayer game, could it be the cause?

EDIT: I confirm. The code is not executed at all. If I put the "ALERT" inside, the message does not appear in console. I don´t know what else to do :(

this is what the code looks like now...

[quote]void CTwohand::Reload( void )
{
	//if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= 100 || m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] >= 100 ) 
	//return;
	edict_t *pPlayer = m_pPlayer->edict( );
	CBaseEntity *pEntity = NULL; 
	while ((pEntity = UTIL_FindEntityInSphere( m_pPlayer, m_pPlayer->pev->origin, 500000.0f)) !=NULL)
	{
		if ( FClassnameIs( pEntity->pev, "monstermaker" ) )
		pEntity->Use( m_pPlayer, m_pPlayer, USE_ON, 0.0f );
	}

	ALERT( at_console, "RELOAD!!\n" );
}
[/quote]
Posted 8 years ago2016-09-28 20:57:23 UTC Post #331796
Add this code to the beginning of the Reload method:
#ifdef CLIENT_DLL
ALERT( at_console, "client\n" );
#else
ALERT( at_console, "server\n" );
#endif
This will tell you if your code is executing on the client or server side. It should output both client and server for every reload, so if it's not doing that, something is very wrong.

The code you're currently using won't work. If it does find an entity, it'll get stuck in an infinite loop. Since it has to find at least one entity in range if it were working (your current weapon), the most logical explanation is that this code is not running on the server side. The client side implements stub functions that allow this code to compile but not function.

Starting the map using the map command causes it to use singleplayer gamerules, but that shouldn't affect monstermakers or utility functions.
Posted 8 years ago2016-09-29 08:03:39 UTC Post #331798
I´ll do it!. ;)

Anyway, I saw this part of code in the beggining of the satchel.cpp file:
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD )

I forgot to add it to the Twohand.cpp file, and maybe it is necessary... :|

And, I have one doubt, if the code runs on server for each player, wouldn´t it be a problem?, I mean, I remember when the v1.0 of the mod has the Radar implemented, and it has also the Util_FindEntitiesInSphere, but it was Clientisde only...
Posted 8 years ago2016-09-29 09:28:38 UTC Post #331799
You don't need those conditions. They're from a long time ago when HL had demo builds and when it came with hardware as a free game to restrict the features included in the game. You won't need it in your mod unless you plan to release limited demos.

If that code runs on the client then it will never do anything. Its implementation on the client is this:
CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius )
{
return 0;
}
It needs to run on the server to work. It's not a problem unless it runs often, in which case you can optimize it by making a list of all monstermakers beforehand and only checking that list for nearby monstermakers.
You'll have to keep track of newly created monstermakers and destroyed monstermakers as well, so i recommend adding the NEW_DLL_FUNCTIONS interface if you haven't already.

Specifically, you'll need to add the callback for entity private data freeing so you are notified of entity removal: https://github.com/SamVanheer/HLEnhanced/blob/8cd53f51e2c5ea33c0f1a2d6b5c57ac98083fd49/game/server/ServerInterface.cpp#L496

This is my version of the callback, in my code i'd add the monstermakers to a list in CBaseEntity::OnCreate and remove them in CBaseEntity::OnDestroy.

The easiest way to handle this if you need to save/restore it would be a static EHANDLE to the first monstermaker that is save/restored as part of global state (SaveGlobalState, RestoreGlobalState functions). A second EHANDLE added to monstermakers as a member variable would point to the next maker in the list.

It's pretty ugly, especially the save/restore as part of global state part. You could do that in worldspawn, since only one instance is created for that, it's up to you. There is a small risk that manually instancing worldspawn again could cause issues, but that's undefined behavior in this game so it's not really your problem. If you don't need save/restore, then you can ignore all of this.

If you don't need save/restore then you can either use the EHANDLE list approach or use a regular list/vector of monstermaker EHANDLEs.

Technically you could use regular pointers since the monstermakers are responsible for adding and removing themselves, but EHANDLEs will make sure that any removal that doesn't trigger the callback won't cause crashes later on.

Once you have the list, finding monstermakers should be relatively simple:
[quote]
for( CMonsterMaker* pMaker = static_cast<CMonsterMaker*>( static_cast<CBaseEntity*>( CMonsterMaker::m_hMakerList ) ); pMaker; pMaker = static_cast<CMonsterMaker*>( static_cast<CBaseEntity*>( pMaker->m_hNextMaker ) ) )
{
if( FStrEq( STRING( pMaker->pev->targetname ), m_pPlayer->TeamID() ) )
{
	pMaker->Use( m_pPlayer, m_pPlayer, USE_ON, 0 );
}
}
[/quote]

The casts are pretty messy thanks to the EHANDLE code not supporting direct casting to entity types. I have a solution in mind for that that should be showing up in HLE soon, if you want to deal with this clutter.

Note that the CMonsterMaker class is declared in a source file, so if you want to directly reference it, you'll need to move its declaration to a header.
Posted 8 years ago2016-09-29 14:01:15 UTC Post #331801
User posted image
AAARRRRRGH, I can only properly understand this:
If that code runs on the client then it will never do anything. Its implementation on the client is this:
Quote:
CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius )
{
return 0;
}
Maybe you can not believe me if I say that I cannot even code the Hello World program. I feeel quite embarrassed now. :( I know that for doing a mod you must know almost the basics of C++, I know I was lucky to arrive here so far without having that basic knowledge, but... Please!!, could I send the full SDK of my mod to you, so you can make all those stuff for me? (desperation mode: ON)
Posted 8 years ago2016-09-29 14:11:05 UTC Post #331802
PM sent Solokiller!!
Posted 8 years ago2016-09-29 17:43:00 UTC Post #331804
I've debugged your code, the problem is exactly what Shepard was talking about. Your weapon sets the max clip value to WEAPON_NOCLIP, which prevents it from ever calling Reload. I set it to INT_MAX (0x7FFFFFFF) and it works just fine, after modifying the while loop to use pEntity as the start entity.

It spawns a steady stream of monsters if you keep pressing it and kill the trolleys as they move, so it seems to be just fine.

I take it you're currently using VS6 to compile this? I recommend upgrading to a newer version since it's a pain in the ass to debug in that version, and it also allows for some standards violating code. If you need help with that, i can make it compatible with any version you want to use. I have 2010 and newer installed, so i can test any of them myself.
I'd also recommend modifying the build settings to output the correct dll name instead of hl.dll, since your mod uses a different name. You can also make it copy the dll over to your mod directory automatically.
Posted 8 years ago2016-09-29 18:36:01 UTC Post #331805
O_o you say that it worked?, IT DOES WORK!?, Weeeeeeeeeeehaaaaaa!!, yes!yes!yes!. xp

Sorry for my excessive enthusiasm, but you cannot understand what this mean to me, it is one of the features of the mod that I thought it could never be made, well, at least with what I know about C++. Btw, is it difficult to install the SDK and VS 2010? I am afraid of changes like that, I remember that I feel like a newbie when I started to change from Photoshop 4 to 5, haha! XD.

I am using MSVC6 since 2003, and, yes, you're right, I think I should start using a new program to code because MSVC6 because it has all those little problems you say (it is boring to change the hl.dll name each time I compile a new version). Btw: How canI do to change hl.dll to zwc.dll and put it into the mod's dll folder?
Posted 8 years ago2016-09-29 18:49:25 UTC Post #331806
The SDK version you're using requires a lot of changes to work in newer versions of C++, but i can help you port it.

Changing the output name is pretty easy, you go into the library settings, Link settings, and change the Output file name.

Copying the file is a bit harder, you'll need to add a post build step to copy it. This works for me: copy /Y "debughl\zwc.dll" "..\..\Xash3D2\ZWC\dlls\zwc.dll"

This will only work for the debug build (and only if your source code is relative to the game directory), i'm not sure if VS6 has variables for configurations or not. The ones that are used in newer versions didn't work, but if you switch over it'll be easier.
Posted 8 years ago2016-09-30 22:45:01 UTC Post #331838
I just want to say, THANKS SOLOKILLER AND SHEPARD62700FR !!! ^^

http://www.moddb.com/mods/zion-warcry/videos/finally-the-reload-call-works
You must be logged in to post a response.