How spanw enemy with weapon from script?

hechelion

Member
Hi.
I have a strange problem.
I have an enemy and a weapon, the weapon is set to fall when you hit an enemy.

if in a stage01.txt, I spawn the enemy with:
Code:
spawn		EnemyA
weapon		WeaponA
flip		0
coords		600 240 0
at			0

Everything work great, The enemy spawn with the weapon, and drop it when he is hit.

*******************************************

Now, I need invoke the enemy from a script, so. I try the next code:
Code:
@script
		clearspawnentry();
		setspawnentry("name", "EnemyA");
		setspawnentry("weapon", "WeaponA");
		setspawnentry("coords", 600,410,0);
		spawn();
	@end_script

The enemy spawn, but without the weapon, is like the line "setspawnentry("weapon", "WeaponA");" was ignored by the engine.

*******************************************

I try change the property weapon after the spawn with:
Code:
@script
		clearspawnentry();
		setspawnentry("name", "EnemyA");
		//setspawnentry("weapon", "WeaponA");
		setspawnentry("coords", 600,410,0);
		void vSpawn = spawn();
		changeentityproperty(vSpawn, "weapon", 3); //WeaponA = weapon index 3
	@end_script
Now, the enemy spawn with the weapon, but when he is hit, change from weapon animation to normal animation (no-weapon) but don't drop the weapon.

*******************************************

I try with "weapnum" instead of "weapon", but it was worse, the enemy appeared without the weapon.

What am I doing wrong?
What is the correct way to summon an enemy with a weapon from one script?

Thank you very much in advance and excuse my English.

 
NONAME01150 said:
when the enemy spawns with weapon "WeaponA" (without script) does he start as the weapon model?
Hi, yes.
The enemy has the weapon, use weapon animation, attack with the weapon, and when is hit by a player, drop the weapon and back to "base" animation.
When I spawn the enemy from a stage.txt file, everything work fine.

The same enemy, the same weapon, even, the same stage, but load the enemy from a script and don't work. I make crazy looking for a mistake, but I don't understood where is the fail.
 
i think i have a solution to that. but it has two problems
1: i never tried this since i barely do entities with weapon models.
2: if the solution works, you will probably have to ditch the "weapon" command from the stage.txt or else it will probably spawn a duplicate of the weapon it was supposed to drop.

@script
clearspawnentry();
setspawnentry("name", "EnemyA");
//setspawnentry("weapon", "WeaponA");
setspawnentry("coords", 600,410,0);
void vSpawn = spawn();
changeentityproperty(vSpawn, "weapon", 3); //WeaponA = weapon index 3
@end_script
Now, the enemy spawn with the weapon, but when he is hit, change from weapon animation to normal animation (no-weapon) but don't drop the weapon.
since having this script makes the enemy load the weapon model but doesn't drop the weapon, i thought you could, like, spawn the weapon on the weapon model's hurt animation. but again, i don't know this will work.
 
Hi, thanks for the suggestion. But it is not the solution I am looking for, I appreciate it.
But having to implement a parallel system when Openbor already has implemented a mechanism that works to drop the weapons, it does not seem correct to me, I prefer to understand why it does not work and correct it.

Obviously, if it were a problem in the Openbor code, in that case a parallel system would have to be implemented to drop the weapons.
But I don't think I'm the only person in the world who has had the need to summon an enemy with a weapon from a script. And I very sure is a very simple solution.
 
hechelion,

I am about to leave for the night, but I can at least explain what is going wrong for you.

When you script something, you are taking TOTAL control. The script does exactly what you say and nothing more. That is what makes script so powerful, but it means you can't leave anything out.

First thing, you need to know how weapons really work. Pay particular attention to what the weapon item does. When an entity picks up a weapon item, the following things happen:

[list type=decimal]
[*]The receiving entity switches to its weapon model matching the weapon ID on weapon item.
[*]The receiving entity has a property that is populated with the weapon item entity's pointer.
[*]The weapon item entity moves to a hidden location in the level (a hardcoded Z position where the camera can't show it).
[/list]

When an entity drops a weapon, the following happens:

[list type=decimal]
[*]The dropping entity returns to its default model.
[*]The weapon item property on dropping entity is used to get weapon item.
[*]The weapon item entity moves to to the dropping entity's exact location.
[*]The dropping entity's property that was previously populated with the weapon item entity's pointer .
[*]The weapon item property on dropping entity is cleared.
[/list]

In your script, you are setting the weapon model of an entity, but you aren't spawning the weapon item and populating the entity with weapon item's pointer. In other words, there's simply no item to drop. This is an easy fix. You just need to add some code lines to spawn the weapon item, move it off screen, and store its pointer in the main entity's weapon item property.

I have a script that does this, it's how Galford works. He starts with his sword, but his default state is actually unarmed. The script arms him on spawn. If he takes a hard enough hit he'll drop the sword, but you can pick it up again.


Only problem is I wrote it using prototype functions that aren't available yet in the stable build. The old functions can do it no problem, I'll just need to back port it for you as an example. I'll try to get you one in next couple of days. Here's what the Galford's full weapon code looks like  right now if you want to see. The function you're interested in is weapon_spawn():

Code:
// Galford loses his sword under certain conditions.
void try_weapon_drop(void ent)
{
	int  force_drop;                      // Incomming knockdown force.
	int  force_damage;                    // Incoming damage.
	int  health = getentityproperty(ent, "health");       //Current HP.
	float pos_y;
	float pos_base;

	void weapon_item;
	char weapon_name;

	// Have a weapon?
	weapon_item = get_entity_property(ent, "weapon_item");

	if (!weapon_item)
	{
		return 0;
	}

	// Is weapon the one we are looking for? Weapon number
	// would be omre optimal, but for whatever reason it
	// seems to return bad data. 
	//weapon_name = get_entity_property(ent, "name");
	
	//if (weapon_name != GALFORD_SWORD)
		
	//	return 0;
	//}

	// Now let's look at conditions.
	force_drop = getlocalvar("drop");

	if (force_drop < GALFOD_DROP_THRESHOLD)
	{
		return 0;
	}


	force_damage = getlocalvar("damage");

	pos_y = get_entity_property(ent, "position_y");
	pos_base = get_entity_property(ent, "position_base");

	// If the damage is less than our threshold AND we're
	// on the ground, then return false.
	if (force_damage < GALFORD_DAMAGE_THRESHOLD && dc_math_difference_float(pos_y, pos_base) <= 0.1)
	{
		return 0;
	}

	log("\n\n do_weapon_drop: " + weapon_item);

	// Lose and drop the weapon.
	do_weapon_drop(ent, weapon_item);

	return 1;
}

// Caskey, Damon V.
// 2019-10-04
//
// Host entity reverts to default model and weapon is dropped 
// as an item pickup. This is more or less a copy of OpenBOR's
// native dropweapon() function so we can replicate its
// functionality manually. If counter falls below a given
// threshold, the weapon breaks instead.
void do_weapon_drop(void ent, void weapon_ent)
{	
	float pos_x;
	float pos_y;
	float pos_z;
	float pos_base;
	float pos_direction;
	float height;
	int dropcount;
	
	// We're going to use our own position for the weapon.
	pos_x = get_entity_property(ent, "position_x");
	pos_y = get_entity_property(ent, "position_y");
	pos_z = get_entity_property(ent, "position_z");
	pos_base = get_entity_property(ent, "position_base");
	pos_direction = get_entity_property(ent, "position_direction");

	set_entity_property(weapon_ent, "position_x", pos_x);
	set_entity_property(weapon_ent, "position_y", pos_y);
	set_entity_property(weapon_ent, "position_z", pos_z);
	set_entity_property(weapon_ent, "position_base", pos_base);
	set_entity_property(weapon_ent, "position_direction", pos_direction);

	//log("\n\n position: " + pos_x + ", " + ", " + pos_y + ", " + )

	// If the flag is 2 or below, we subtract the flag's
	// value from weapon counter.
	//if (flag < 2)
	//{
	//	self->weapent->modeldata.counter -= flag;
	//}
	
	
	// Get current drop count, and start at 0 if we don't have one.
	dropcount = getlocalvar(GALFORD_WEAPON_DROP_COUNT_KEY);

	if (!dropcount)
	{
		dropcount = 0;
	}

	// Increment counter and save.
	dropcount++;
	setlocalvar(GALFORD_WEAPON_DROP_COUNT_KEY, dropcount);

	// Set animation control to weapon entity.
	dc_disney_set_entity(weapon_ent);

	// If we have dropped weapon too many times, use follow2 
	// animation to put weapon out of play. Otherwise just
	// use follow1 (weapon falls to ground as item).
	if (dropcount >= GALFORD_WEAPON_MAX_DROP)
	{
		dc_disney_play_animation(openborconstant("ANI_FOLLOW2"));
		setlocalvar(GALFORD_WEAPON_DROP_COUNT_KEY, NULL());
	}
	else
	{
		dc_disney_play_animation(openborconstant("ANI_FOLLOW1"));
	}

	// Clear our tracking variable that keeps the weapon entity pointer.
	set_entity_property(ent, "weapon_item", NULL());

	changeentityproperty(ent, "weapon", GALFORD_WEAPON_UNARMED);

}


// Mimics spawning with a weapon pick up. 
void weapon_spawn()
{
	void ent = getlocalvar("self");
	void spawn = dc_gauntlet_quick_spawn("Justice_Sword");
	int animation;

	// Item spawns at our position, but hidden on Z axis.
	set_entity_property(spawn, "position_x", get_entity_property(ent, "position_x"));
	set_entity_property(spawn, "position_y", get_entity_property(ent, "position_y"));
	set_entity_property(spawn, "position_z", openborconstant("ITEM_HIDE_POSITION_Z"));

	// Make sure engine knowns this is a weapon type spawn.
	set_entity_property(spawn, "spawn_type", openborconstant("SPAWN_TYPE_WEAPON"));

	// Now we "pick up" the item. Our weapon changes and the item
	// pointer is stored in our weapon item property, just like
	// the engine's native pickup. 
	set_entity_property(ent, "weapon_item", spawn);
	changeentityproperty(ent, "weapon", 1);

	
}

DC
 
Hi Damon Caskey.
Thanks so much for the explanation. now I have much clearer how it works.
I'm going to try to create a function that does the same as your code does, but for the stable version of Openbor.
If you have time and can write the same code for the stable version, I will appreciate it.

If I may, there is something I still do not understand.
When from stage01.txt I invoke an enemy with:
weapon WeaponA
I understand that statement tells the engine to create the weapon and associate the pointer with the entity that is loading.

Why doesn't the same instruction work when loaded into the buffer with "setspawnentry (" weapon "," WeaponA ");"?
 
Back
Top Bottom