float to int issue <solved>

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
ArchAngel777
Posts: 19
Joined: Sat Jun 10, 2023 1:06 am
Preferred Pronouns: He/Him
Operating System Version (Optional): W10
Graphics Processor: nVidia (Modern GZDoom)

float to int issue <solved>

Post by ArchAngel777 »

I have a mana draining function that drains mana based on percentage of the damage dealt.

Code: Select all

void A_CustomMeleeAttack2(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true)
	{
	// call original function
	A_CustomMeleeAttack(damage, meleesound, misssound, damagetype, bleed);
	
	// perform Mana drain
	if (CheckMeleeRange(-1))
		{
		A_TakeFromTarget("Mana1", (int)(floor(damage/2)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);
		A_TakeFromTarget("Mana2", (int)(floor(damage/3)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);
		A_TakeFromTarget("Mana3new", (int)(floor(damage/4)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);
		health += damage;
		//if (health > SpawnHealth() ) { health = SpawnHealth(); }
		}
	}
The problem is, converting the float coming from the division of damage into an int, isn't working as expected. So, the mana1 drain seems to work just fine, no issues. But the mana2 and mana3 draining will often result in a sudden set to 0. For example, I may have 160 mana2, than it suddenly becomes 0. I assume some kind of data type issue is occurring. If anyone has any ideas, I'd really appreciate it. I can have all 3 mana types drain by damage/2 and that works fine, but I wanted the stronger mana types to drain at a lower percentage for balancing reasons.
Last edited by ArchAngel777 on Wed Jul 05, 2023 12:47 am, edited 1 time in total.
User avatar
MartinHowe
Posts: 2089
Joined: Mon Aug 11, 2003 1:50 pm
Preferred Pronouns: He/Him
Location: East Suffolk (UK)

Re: float to int issue

Post by MartinHowe »

I'm not sure what the floor function is for here - damage is an int, so are 2 and 3; so the result should be an int anyway, and it will be truncated towards zero. So (int)(floor(X/Y))if X and Y are both int is like:

1) Divide X by Y, giving Z, where Z is an int.
2) Promote Z to double. It will have a zero fractional part.
3) Use floor to remove the (non-existent) fractional part of Z, giving ZZ, which is double.
4) Round down (truncate) ZZ to int.

You might as well just divide damage by 2 (or 3) directly and have done with it. I'd say try it and then see what happens.

(Although not necessary here, if you actually did want to get a double from the division so that there is a fractional part, using 3.0 instead of 3 should do it; this is why a lot of the inbuilt code is littered with integers suffixed by a decimal point so as to make them double literals instead of ints).
ArchAngel777
Posts: 19
Joined: Sat Jun 10, 2023 1:06 am
Preferred Pronouns: He/Him
Operating System Version (Optional): W10
Graphics Processor: nVidia (Modern GZDoom)

Re: float to int issue

Post by ArchAngel777 »

Well my first attempt was just "damage/4" which caused the same issue. I than tried "round(damage/4)" and than finally "(int)(damage/4)" until I ran out of ideas. Either case, the result is the same. When dividing by any number other than 2, it will occasionally set mana to 0. Not only that, but /3 or /4 will also sometimes result in losing way MORE mana than /2. The wiki says all rounding functions return a float, and casting doesn't seem to solve the issue, so I am fresh out of ideas now. I also tried "damage/4.0" and every combination of all these approaches. :(

If I can't figure this out, I'm thinking I'll have to do something hacky, like randomly drain one type of mana, but with a higher chance of draining mana1 versus the other mana types.
User avatar
MartinHowe
Posts: 2089
Joined: Mon Aug 11, 2003 1:50 pm
Preferred Pronouns: He/Him
Location: East Suffolk (UK)

Re: float to int issue

Post by MartinHowe »

Hmm. Have you tried putting logging statements in the function so you can see exactly what damage is coming in in the first place: ALogInt(damage);? Or even finding how much damage was actually caused?

Code: Select all

void A_CustomMeleeAttack2(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true)
	{
	// Get  Health of target before the attack
	int oldHealth = target.Health;
	
	// call original function
	A_CustomMeleeAttack(damage, meleesound, misssound, damagetype, bleed);

	// Get actual damage dealt
	int actualDamage = oldHealth - target.Health;
	A_LogInt(actualDamage);
	
	// perform Mana drain
	if (CheckMeleeRange(-1))
		{
		A_TakeFromTarget("Mana1", (int)(floor(damage/2)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);
		A_TakeFromTarget("Mana2", (int)(floor(damage/3)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);
		A_TakeFromTarget("Mana3new", (int)(floor(damage/4)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);
		health += damage;
		//if (health > SpawnHealth() ) { health = SpawnHealth(); }
		}
	}
ArchAngel777
Posts: 19
Joined: Sat Jun 10, 2023 1:06 am
Preferred Pronouns: He/Him
Operating System Version (Optional): W10
Graphics Processor: nVidia (Modern GZDoom)

Re: float to int issue

Post by ArchAngel777 »

The damage, actualDamage and the (damage/4) all log the expected values. So perhaps the issue is with the A_TakeFromTarget() function?
Jarewill
 
 
Posts: 1853
Joined: Sun Jul 21, 2019 8:54 am

Re: float to int issue

Post by Jarewill »

If the amount parameters in A_TakeFromTarget is set to 0, it will take away all items instead of none, which is what I'd guess is happening here.
Try adding checks to see if the amount isn't equal to 0 first before taking away:

Code: Select all

If((int)(floor(damage/2))!=0){A_TakeFromTarget("Mana1", (int)(floor(damage/2)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);}
If((int)(floor(damage/3))!=0){A_TakeFromTarget("Mana2", (int)(floor(damage/3)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);}
If((int)(floor(damage/4))!=0){A_TakeFromTarget("Mana3new", (int)(floor(damage/4)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);}
User avatar
randi
Site Admin
Posts: 7749
Joined: Wed Jul 09, 2003 10:30 pm
Contact:

Re: float to int issue

Post by randi »

I would like to point out that there are no floats here, until one is created with floor().

damage is an int:
ArchAngel777 wrote: Sun Jul 02, 2023 11:47 pm

Code: Select all

void A_CustomMeleeAttack2(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true)
ArchAngel777 wrote: Sun Jul 02, 2023 11:47 pm

Code: Select all

		A_TakeFromTarget("Mana1", (int)(floor(damage/2)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);
		A_TakeFromTarget("Mana2", (int)(floor(damage/3)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);
		A_TakeFromTarget("Mana3new", (int)(floor(damage/4)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);
damage/2, damage/3, and damage/4 are all integer divisions. After division, they are promoted to floats to pass to floor() (which won't do anything because ints have no fractional part), then they get converted back to ints. In other words, here (int)(floor(damage/2)) is the same as damage/2 with extra work.

(Or what MartinHowe explained in detail above, but it doesn't seem to have been heeded in subsequent posts. Jarewill has the correct answer, although it still has the whole (int)floor(int) thing going on.)

This would probably be a good case for another flag for A_TakeFromTarget().
ArchAngel777
Posts: 19
Joined: Sat Jun 10, 2023 1:06 am
Preferred Pronouns: He/Him
Operating System Version (Optional): W10
Graphics Processor: nVidia (Modern GZDoom)

Re: float to int issue

Post by ArchAngel777 »

Jarewill wrote: Tue Jul 04, 2023 3:36 am If the amount parameters in A_TakeFromTarget is set to 0, it will take away all items instead of none, which is what I'd guess is happening here.
Try adding checks to see if the amount isn't equal to 0 first before taking away:

Code: Select all

If((int)(floor(damage/2))!=0){A_TakeFromTarget("Mana1", (int)(floor(damage/2)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);}
If((int)(floor(damage/3))!=0){A_TakeFromTarget("Mana2", (int)(floor(damage/3)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);}
If((int)(floor(damage/4))!=0){A_TakeFromTarget("Mana3new", (int)(floor(damage/4)), TIF_NOTAKEINFINITE, AAPTR_DEFAULT);}
ahh that was it. I wasn't aware of that being the case. I did see something like that mentioned in the wiki but at first glance I wasn't quite sure what it meant. Thanks for the help! :)
Post Reply

Return to “Scripting”