ID:2642792
 
(See the best response by Nadrew.)
Code:
//Main.dm
world
turf = /turf/grass



mob
Login()
src.LoadPlayer()
..()

var
Hp = 0
Damage = 0
Wealth = 0
ExpGive = 0
Exp = 0
ExpNext=0
Level = 1
Str = 1
Def = 1
critRank = 1
proc
LoadPlayer()
var/mob/Player/P = new()
P.client = src.client
P.Move(locate(/turf/grassStart))


DeathCheck(mob/Killer)
if(src.Hp < 1)
LevelUp(Killer)
del(src)
..()

LevelUp(mob/M as mob)
if(usr.Exp >= usr.ExpNext)
usr.Level += 1
world<<"Level Up, Level: [usr.Level]"
usr.Exp = usr.Exp - usr.ExpNext
if(Level == 5)
critRank+=1
if(Level == 10)
critRank+=1
usr.Statgain()

Statgain(S,D)
world << "You have gained [S] Str and [D] Defense!"

TakeDamage(Dmg,mob/Source)
Source.Hp -= Dmg
Source.DeathCheck(Source)


//EnemyMain.dm

mob/Enemy/Weak
icon = 'Enemy.dmi'
icon_state = "Weak"

Hp = 10
ExpGive = 25
Def = 3

DeathCheck(mob/Enemy/Weak/M)
usr.Exp += ExpGive/2
var/obj/Ohms/G = new(loc)
G.value = 1
..()

mob/Enemy/Elite
icon='Enemy.dmi'
icon_state="Elite"

Hp= 150
Def = 15
ExpGive = 100

DeathCheck(mob/Enemy/Elite/M)
usr.Exp += ExpGive /2
var/obj/Ohms/G = new(loc)
G.value = rand(10,500)
..()

//PlayerMain.dm

mob/Player

Hp = 100

Level = 1
ExpNext = 100
Str = 5
Def = 10
critRank = 1
var
strGain=1
defGain=1

Statgain(S,D)
S = strGain
D = defGain
Str += strGain
Def += defGain
strGain += round(1.05 *rand(1,5))
defGain += round(1.05 *rand(1,5))
..()






verb
say(msg as text in view())
set category = "Social"
view() <<"[usr] says: [msg]"

OOC(msg as text)
set category = "Social"
world << "[usr]: [msg]"


Attack(mob/M in oview(1))
set category = "Combat"
Damage = Str - M.Def + rand(critRank*-10,critRank*10)
if(Damage < 0)
Damage = 0
if (M.Hp > 0)
view() << "[usr] hit [M] for [Damage] Damage!"
TakeDamage(Damage,M)
else if (M.Hp <= 0)
view() << "[M] Is Already Dead"


ScanMob(mob/M in oview(3))
set category = "Combat"
usr << "[M.name] : Hp: [M.Hp], Exp Gain: [M.ExpGive]"


CheckStats()
world << "Ohms: [usr.Wealth], Exp: [usr.Exp], Level: [Level], Strength: [Str], Defense: [Def]"

icon = 'player.dmi'


Problem description: Alright I've been racking my brain trying to figure this out. I've ran the code multiple times with different items commented out so I know that the DeathCheck() of the Mob is what is making this happen. Or atleast I hope.

When the mob dies it drops up to 7 different gold items. I had it at a random value between 1 and 50 but to see if it would change I made the drop value one.

I can't figure out for the life of me what's making it drop multiple gold.

Also my gold is called Ohms.

I've included the Player Script, the Enemy Script, and the Main script that all might be adding to the problem but from what I can tell, the problem stems from the mob/Enemy DeathCheck()s


Best response
You're calling DeathCheck() wrong, the check that checks for health is at the top-most definition, but the code inside of the children's DeathCheck() procs doesn't actually have that check until you use ..() inside of them.

obj/proc/MyProc()
world << "A" // Outputs "A"

obj/child/MyProc()
world << "B"
..() // Outputs "B" then "A"

obj/otherchild/MyProc()
..()
world << "C" // Outputs "A" then "C"


So you're triggering the code that spawns the gold object every time you attack them, and not just when you kill them. You likely want to utilize the return value of the parent to make sure the child proc should execute.

obj/proc/MyProc()
if(something)
return 1
return 0

obj/child/MyProc()
if(..()) // Only passes if the parent proc returns true
// Do something
else
// The parent proc returned 0!


But you're gonna run into an issue with that due to your del(src) line, which is going to cease the object's existence, and that'll stop any running procs. So you don't want that bit to be done until the end, which means either throwing it into the child's DeathCheck(), or not using del() at all, but reusing the mob. So instead of deleting it, you'd just hide it from the world for a period of time, then move it back to its original location with all of its stats restored, this'll let you keep using the mob without the overhead of creating or destroying it. If you still want to delete it, you'd just do so after the code that spawns the reward.

More ideally, you'd have a separate proc that handles special things to do before getting rid of the mob, that gets called right before you delete/hide it, then you'd use that proc to do things like drop loot and the sort.

mob/proc/OnDeath()


mob/proc/DeathCheck()
if(src.health <= 0)
OnDeath()
del(src)

mob/monster/OnDeath()
DropLoot()
GiveEXP()
// For example
I also just noticed you're using the procs wrong, you should be using "M" and not "usr" in them, you're passing the attacker as the proc's argument, it should also be typecast as /mob instead of /mob/enemy/whatever

To add, instead of having a unique proc override for each instance of your mob, you really just need your ExpGive and something like a GoldGive variable, then you'd just award a generic award upon any death of a mob that has those variables set.

mob/var
ExpGive = 0
GoldGive = 0
mob/proc/DeathCheck(mob/killer)
if(health <= 0)
if(ExpGive)
killer.exp += ExpGive
// Check levelup stuff
if(GoldGive)
killer.gold += GoldGive

mob/enemy
weak
GoldGive = 10
// You could set this to your rand() value when you spawn the enemy, by using something like a GoldGiveLow and GoldGiveHigh value set and passing those through rand() in New() or your own proc
ExpGive = 10

strong
GoldGive = 20
ExpGive = 20
In response to Nadrew
//Main.dm

world
turf = /turf/grass



mob
Login()
src.LoadPlayer()
..()

var
Hp = 0
Damage = 0
Wealth = 0
ExpGive = 0
Exp = 0
ExpNext=0
Level = 1
Str = 1
Def = 1
critRank = 1
goldDrop = 0
proc
LoadPlayer()
var/mob/Player/P = new()
P.client = src.client
P.Move(locate(/turf/grassStart))


DeathCheck(mob/Killer)
if(src.Hp < 1)
return 1
else return 0

LevelUp(mob/M)
if(M.Exp >= M.ExpNext)
M.Level += 1
M<<"Level Up, Level: [M.Level]"
M.Exp = M.Exp - M.ExpNext
M.Statgain()

Statgain(S,D)
Str += S
Def += D
src << "You have gained [S] Str and [D] Defense!"


TakeDamage(Dmg,mob/Source,mob/DmgTaker)
DmgTaker.Hp -= Dmg
DmgTaker.DeathCheck(Source)

OnDeath(exp,ohms,mob/Killer)
GiveExp(exp,Killer)
DropLoot(ohms)

DropLoot(ohms)
var/obj/Ohms/G = new(loc)
G.value = ohms

GiveExp(exp,mob/Killer)
usr.Exp += exp
LevelUp(Killer)

//PlayerMain.dm

mob/Player

Hp = 100

Level = 1
ExpNext = 100
Str = 5
Def = 10
critRank = 1
var
strGain=1
defGain=1

Statgain(S,D)
S = strGain
D = defGain
strGain += round(1.05 *rand(1,5))
defGain += round(1.05 *rand(1,5))
..()






verb
say(msg as text in view())
set category = "Social"
view() <<"[usr] says: [msg]"

OOC(msg as text)
set category = "Social"
world << "[usr]: [msg]"


Attack(mob/M in oview(1))
set category = "Combat"
Damage = Str - M.Def + rand(critRank*-10,critRank*10)
if(Damage < 0)
Damage = 0
if (M.Hp > 0)
view() << "[usr] hit [M] for [Damage] Damage!"
TakeDamage(Damage,usr,M)
else if (M.Hp <= 0)
view() << "[M] Is Already Dead"
del(M)


ScanMob(mob/M in oview(3))
set category = "Combat"
usr << "[M.name] : Hp: [M.Hp], Exp Gain: [M.ExpGive]"


CheckStats()
world << "Ohms: [usr.Wealth], Exp: [usr.Exp], Level: [Level], Strength: [Str], Defense: [Def]"

icon = 'player.dmi'


//EnemyMain.dm

mob/Enemy/Weak
icon = 'Enemy.dmi'
icon_state = "Weak"

Hp = 10
ExpGive = 25
Def = 3

DeathCheck(mob/Killer)
if(..())
goldDrop = rand(1,25)
OnDeath(ExpGive,goldDrop,Killer)
del(src)

mob/Enemy/Elite
icon='Enemy.dmi'
icon_state="Elite"

Hp= 150
Def = 15
ExpGive = 100
goldDrop = 0

DeathCheck(mob/Killer)
if(..())
goldDrop = rand(5,100)
OnDeath(ExpGive,goldDrop,Killer)
del(src)


Ok so I feel like you helped me alot. Not only to understand what exactly I was doing because now I realize I didn't have a clue. But also to get it working.

This is what I have now. And it works perfect, or as good as I wanted to work. If it can be improved still let me know. I realize I can pass as many arguments as I want but I might be passing too many to too many different procs.As it stands I'm not sure, just trying to figure this out as I go. With other languages I always follow a tutorial and get to a point where im stuck and discouraged but byond dm feels like I can do it all by myself if I just take the time.

But if there's any way I can improve this let me know, next imma read up on how to spawn anything. I realize I did it already with the gold but that was from searching how to spawn gold and i dont know if objs work the same as a mob.