ID:263951
 
Applicable Configuration:
BYOND Version: 414.979
Operating System: Windows XP
Web Browser: Internet Explorer 7
Game/Hub(s): hub://
Video Card (for graphics bugs):

Descriptive Problem Summary: When an obj is made into a subcategory, another obj in the same sub-category may pass down it's characteristics.

Numbered Steps to Reproduce Problem: Make an obj with characteristics, make the next. Badda-bing-badda-boom.

Code Snippet (if applicable) to Reproduce Problem:
obj/projectile    // Using a projectile subtype so
// similar objects like bullets,
// arrows, or darts can be added easily.

Aqua_Undo
//blah blah blah

Bump(atom/A)
if(ismob(A))
if(shooter.hp <= shooter.mhp-7)
shooter.hp += 7
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
victim.hp -= 15
victim.Deathcheck()
view(shooter)<<"[shooter] drinks some water that comes off from his spell!"
else
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
victim.hp -= 15
else
view(A)<<"[shooter]'s spell missed their intended target and hit [A]!"
obj/projectile // Using a projectile subtype so
// similar objects like bullets,
// arrows, or darts can be added easily.

Calx
//blah blah blah

Bump(atom/A)
if(ismob(A))
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
victim.hp -= 15
victim.Deathcheck()
else
view(A)<<"[shooter]'s spell missed their intended target and hit [A]!"
obj/projectile // Using a projectile subtype so
// similar objects like bullets,
// arrows, or darts can be added easily.

Aero
//blah blah blah

Bump(atom/A)
if(ismob(A))
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
step(victim, shooter.dir)
victim.hp -= 15
victim.Deathcheck()
else
view(A)<<"[shooter]'s spell missed their intended target and hit [A]!"


Expected Results: That each spell used will have their own chararteristics.

Actual Results: Each spell has the chararacteristics listed plus Aero's step().

Does the problem occur:
Every time? Or how often? Every time
In other games? Uknown
On other computers? Unknown
In other user accounts? Unknown

When does the problem NOT occur? When you make it move on

Workarounds: Make a new obj that does basically nothing that is in the sub-category.

Other Information: It is unknown to me if this works with all objs since I've only tried it with projectiles.

EDIT: I ahve recently discovered that characteristics are shared even if there is no subtype.
Indent Bump()s + Bump() Coding one more, otherwise last listed applies to all projectiles. (not on comp atm will edit with correct code in morning)

Edit:
obj/projectile 
Aqua_Undo
Bump(atom/A)
if(ismob(A))
if(shooter.hp <= shooter.mhp-7)
shooter.hp += 7
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
victim.hp -= 15
victim.Deathcheck()
view(shooter)<<"[shooter] drinks some water that comes off from his spell!"
else
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
victim.hp -= 15
else
view(A)<<"[shooter]'s spell missed their intended target and hit [A]!"

obj/projectile
Calx
Bump(atom/A)
if(ismob(A))
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
victim.hp -= 15
victim.Deathcheck()
else
view(A)<<"[shooter]'s spell missed their intended target and hit [A]!"

obj/projectile
Aero
Bump(atom/A)
if(ismob(A))
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
step(victim, shooter.dir)
victim.hp -= 15
victim.Deathcheck()
else
view(A)<<"[shooter]'s spell missed their intended target and hit [A]!"
In response to Quaddw
Full code:

obj/projectile    // Using a projectile subtype so
// similar objects like bullets,
// arrows, or darts can be added easily.

Aqua_Undo
icon='Aqua Eructo.dmi'


density=1


New(start_loc, direction, shooter, delay)
src.shooter=shooter
if(!Move(start_loc, direction)) del src // The initial move is here in case someone is on the first tile.
spawn(delay)
while(step(src, direction))
sleep(delay)
del src

Bump(atom/A)
if(ismob(A))
if(shooter.hp <= shooter.mhp-7)
shooter.hp += 7
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
victim.hp -= 15
victim.Deathcheck()
view(shooter)<<"[shooter] drinks some water that comes off from his spell!"
else
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
victim.hp -= 15
else
view(A)<<"[shooter]'s spell missed their intended target and hit [A]!"
obj/projectile // Using a projectile subtype so
// similar objects like bullets,
// arrows, or darts can be added easily.

Calx
icon='attacks.dmi'
icon_state="calx"


density=1

New(start_loc, direction, shooter, delay)
src.shooter=shooter
spawn(delay)
while(step(src, direction))
sleep(delay)

Bump(atom/A)
if(ismob(A))
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
victim.hp -= 15
victim.Deathcheck()
else
view(A)<<"[shooter]'s spell missed their intended target and hit [A]!"
obj/projectile // Using a projectile subtype so
// similar objects like bullets,
// arrows, or darts can be added easily.

Aero
icon='attacks.dmi'
icon_state = "wind"


density=1


New(start_loc, direction, shooter, delay)
src.shooter=shooter
if(!Move(start_loc, direction)) del src // The initial move is here in case someone is on the first tile.
spawn(delay)
while(step(src, direction))
sleep(delay)
del src

Bump(atom/A)
if(ismob(A))
var/mob/victim=A
view(A)<<"[shooter] hit [victim]!"
step(victim, shooter.dir)
victim.hp -= 15
victim.Deathcheck()
else
view(A)<<"[shooter]'s spell missed their intended target and hit [A]!"


It wont allow me to indent the bump proc without coming up with errors.
In response to Demon_F0rce
Make sure you indent everything below a certain node path like "Aero"... just the Bump() will most probably not work, the compiler will think you're trying to make it belong to the proc above it or something.
Though, your system shouldn't even be like this. You seem to be aware of object inheritance (well, though, not totally aware of indentation...) - use it. There's no need to "duplicate" code and override the same procs over and over to do the exact same, or almost same things. That already shows you there is a big flaw in your design, in any system.
Repeating code == bad. Override the Bump(), New() etc once for the parent, obj/projectile so it is shared by all projectiles; do your generic stuff there, initializing variables, moving (which you should abuse a built-in proc for really, walk()), etc. Then handle any specific differences threw variables and occasional overrides (in which you call the parent instead of repeating code).
In response to Kaioken
I think I understand what you're saying. And I think I understand what I should do... Thanks.

Only problem is that I'm not sure what to do with Bump since my Bump is different for each projectile. Some projectiles do more damage than others, and some have different effects than others. Some projectiles do no damage and simply create some kind of effect.

EDIT: I just realised that Calx will the New() proc kept too since it doesn't delete itself after use.
In response to Demon_F0rce
Demon_F0rce wrote:
I think I understand what you're saying. And I think I understand what I should do... Thanks.

I'm glad. :)

Only problem is that I'm not sure what to do with Bump since my Bump is different for each projectile. Some projectiles do more damage than others,

Yes, of course. Use variables and set each type's damage (and other) variables accordingly, then in the Bump() proc do the relative damage with the variable.

and some have different effects than others. Some projectiles do no damage and simply create some kind of effect.

You could create a new proc for that: /obj/projectile/proc/Effect() (or perhaps Affect). It would be called from Bump() (or somewhere else; this also provides more flexibility, you can initiate the damage/effect from anywhere), and the default would be just the usual damage:
obj/projectile
var/damage = 5 //generic var discussed earlier. default value is 5
proc/Effect(mob/M)
if(M) //just a failsafe, even though M should really be valid if it got threw here. you could also check M's type
M.TakeDamage(src.damage)
viewers(src) << "[M] is hit by [src.owner]'s [src]!"

Then you override that proc for special effects.
obj/projectile
paralyze_ray
damage = 3
Effect(mob/M) //overidding
..() //this calls the default action above (gives M 3 damage and announces hit; you could also set damage=0 for this projectile if you wanted)
M.paralyzed = 1 //paralyze, or whatever special effect you have in mind


EDIT: I just realised that Calx will the New() proc kept too since it doesn't delete itself after use.

Well you could also use a var like that, or istype(), if projectiles that don't delete themselves aren't common. Also I don't think you should handle deleting over there in New(), though it doesn't matter that much. In any case, keep the New() clean; especially since your manual movement there is straightforward, the built-in walk() proc can do the same, so might as well use it (you should favor for built-in procs for pretty obvious reasons; its easier, faster, and more efficient (things built-in to the DM language are naturally faster than "softcoding" the same effect into your DM code). If you want to do something after each step or something similar, override the movement procs (Entered(), etc), though for most purposes you won't require overriding more than Move().
You can delete the projectile if needed simply at the end of Bump().
obj/projectile
var/stays = 0
Calx/stays = 1 //variable override for Calx subtype
Bump(mob/M)
if(istype(M) //if M is really a mob
src.Effect(M) //Effect() him!
...
if(!src.stays) del src //delete, if wanted
//as I said, you could also use instead:
if(!istype(src,/obj/projectile/Calx))


A projectile system also happens to be my only demo (*plug*, I guess). While not being the best I could make it, and overflooded with comments, I believe it explains the basic parts of such a system well as well as most of the points I explained above. You should probably check it out.
In response to Kaioken
Okay. So I've got this:
obj/projectile
var/damage=0
var/owner
var/odir
var/delay=3
proc/Effect(mob/A)
A.hp -= damage
A.mhp += damage/2
view(A) << "[A] has been hit by [src.owner]'s spell!"
A.Deathcheck()
//if(!istype(src,/obj/projectile/Calx))
del src
obj/projectile // Using a projectile subtype so
// similar objects like bullets,
// arrows, or darts can be added easily.

Flippendo
icon='attacks.dmi'
icon_state = "flippendo"


density=1
damage=5

Bump(mob/A)
Effect(A)
..()
step(A,src.dir)

mob/Spell
verb
Flippendo()
set category = "Spells"
if(wandout == 1)
if(usr.pertr==0)
if(confound == 1)
usr.random=rand(1,2)
if(random == 1)
view(usr) << "<font color = teal><b><u>[usr]</b></u><font color = teal>:<i><font color = green> Flippendo!"
var/obj/projectile/Flippendo/P = new(null,usr)
P.loc = usr.loc
P.dir = usr.dir
P.owner = usr
P.odir = usr.dir
walk(P,P.odir)
if(random == 2)
usr << "You raise your wand, only to find the spell leave your grasp"
return
else
view(usr) << "<font color = teal><b><u>[usr]</b></u><font color = teal>:<i><font color = green> Flippendo!"
var/obj/projectile/P = new/obj/projectile/Flippendo
P.loc = usr.loc
P.dir = usr.dir
P.owner = usr
P.odir = usr.dir
walk(P,P.odir)
else
usr<<"You cannot cast spells"
else
usr << "You must have your wand out!"

Works fine. Except my enemy wont step back.
In response to Demon_F0rce
        del src


Once src has been deleted, all procs belonging to it are immediately halted.
In response to Garthor
I see. So I should delete the object after step()?

EDIT: Tried puting del src after step() but hte object wont delete.
In response to Demon_F0rce
You should clean your code up a bit... order it right, fix indentation, etc, and there's of course no need to put another "/obj/projectile" line at all since the code was already at that node in that spot. Looks like the code under Flipendo is meant to belong to it, but it isn't indented to it.
You've also missed it somewhat on the Bump() proc. Again, looks like you meant it to belong to Flipendo (you really need to get indentation sorted out, read tutorials like ZBTs and the DM Guide if you're missing on the basics), as the step() is there. But such an effect like step() should be in... the Effect() proc. Flipendo's Effect() proc. Bump() should probably only have one override in your whole system, at the base obj/projectile node, and all it should do is pretty much call Effect() and then delete src. You override specific projectiles Effect() proc to... determine their effect, like step() or whatever. I suppose you also could just move the 'de l src' part from the main Bump() to the main Effect() where you have it now, depending on what your 'staying' projectiles do. Also always keep in mind what Garthor said, when dealing with objects - if src is deleted all it's procs are killed.

As for your verbs, well... they're not pretty at all. But I'll leave them for later, or for someone else, if they at least work for now. You should really also use a single dynamic verb for shooting spells instead of a hardcoded verb for each type of spell (that's admittedly how it is in my demo, but like I said it's not perfect). You might also want/need to add a mob/proc/Shoot() for that, and a mob/list/spells for keeping track if the spells a mob can cast if you don't have such a thing already.
In response to Kaioken
Thanks. I think that I've finally got this sorted out.