ID:156025
 
Ive been trying to make a clone that when you click a verb that it makes a clone of yourself and then your view goes into its view and you can move it with your arrow keys just like it was you but if someone hits it once it disappears and your view goes back to normal
This is what i have from my old game its probably crap but it does whats sorta asked.

mob/var/locked
client
var/mob/Controlling//client var that is a mob
North()
if(Controlling)//if your control var is not empty, when you press north they will move north
step(Controlling,NORTH)
else
if(!usr.locked)
..()
else
return
South()
if(Controlling)
step(Controlling,SOUTH)
else
if(!usr.locked)
..()
else
return
East()
if(Controlling)
step(Controlling,EAST)
else
if(!usr.locked)
..()
else
return
West()
if(Controlling)
step(Controlling,WEST)
else
if(!usr.locked)
..()
else
return

var/shadowed=0
mob
verb
Shadow_Clone()

var/mob/ShadowClone/SA = new/mob/ShadowClone(locate(src.x+1,src.y,src.z))
SA.icon = usr.icon
SA.icon_state = usr.icon_state
SA.overlays += usr.overlays
SA.name = usr.name
flick("smoke",SA)
SA.Death()
if(shadowed==0)
usr.client.perspective = EYE_PERSPECTIVE
usr.client.eye = SA
usr.client.Controlling = SA
shadowed++
sleep(50)
usr.client.perspective = EYE_PERSPECTIVE
usr.client.eye = usr
usr.client.Controlling = usr
del(SA)
shadowed=0
if(shadowed==1)
var/mob/ShadowClone2/SA2 = new/mob/ShadowClone2(locate(src.x+1,src.y,src.z))
SA2.icon = usr.icon
SA2.icon_state = usr.icon_state
SA2.overlays += usr.overlays
SA2.name = usr.name
flick("smoke",SA2)
sleep(30)
flick("smoke",SA2)
del(SA2)
How about setting client.mob to the clone?
In response to Toadfish (#2)
You're doing it wrong. 0.o

You need to create a ghost version of yourself at your current location then continue using your current state. Much easier. Hmm..
In response to Kyle_ZX (#3)
Are you responding to me? Try saying that in English...
In response to Toadfish (#4)
Okay, I'll make this really simple for you. At the moment you are creating something completely new and swapping control to it. I'm saying that this is a very illogical way of doing it. Instead create something that holds the players place, often referred to as a ghost. Once that is done you change the player into what you want. No controls are switched, etc etc etc.

Also in the future if someone is trying to help you, mocking them is not a good idea.
In response to Toadfish (#2)
Toadfish wrote:
How about setting client.mob to the clone?

Changing client.mob introduces a few problems in the general case, notably logging in/out, saving, and verbs (especially if the original mob is of a different type than the 'clone' mob). It's generally not worth it unless you fleshed out your code to consider all of the side-effects.

If you just want to be able to move the clone, and program some interactions, then changing client.mob should not be necessary.
In response to Kyle_ZX (#5)
Kyle_ZX wrote:
Okay, I'll make this really simple for you. At the moment you are creating something completely new and swapping control to it. I'm saying that this is a very illogical way of doing it. Instead create something that holds the players place, often referred to as a ghost. Once that is done you change the player into what you want. No controls are switched, etc etc etc.

Your proposed method doesn't make much sense either. It seems like you're trading one problem over another, which is the fact that you're not actually controlling a clone. Doing it this way would require you to program clone-related business logic into your main character's business logic, which makes no sense when you can just do clone-related logic inside of a separate clone object. This also requires having to deal with changing and reverting some clone properties (for example, what if the clone had lower health, or half your stats?) on your actual player.
In response to Unknown Person (#7)
It all depends on exactly what you want to do. If your ghost is not expected to do anything then it's fine where it is. If not then yes, you'd need to program it. As far as I can tell the person just wants to have the player look like it's something it isn't.
In response to Kyle_ZX (#8)
Kyle_ZX wrote:
It all depends on exactly what you want to do. If your ghost is not expected to do anything then it's fine where it is. If not then yes, you'd need to program it. As far as I can tell the person just wants to have the player look like it's something it isn't.

The requirements are important in knowing how to implement the feature, but as I mentioned before, that particular solution seems to be in the nature of trading convenience (that is, of not having to program movement) for the complication of side effects.

Arguably, I'd think that overriding movement/perspective from the client is an easier task than swapping positions, and ensuring the placeholder and mimic clone react the way they are supposed to. This is pretty true in any general context, really, not just in this clone example.
In response to Unknown Person (#6)
(Deleted my post when trying to press edit, ha!)

Hmm, I'm not sure I understand the concerns. Let me know if I overlooked something: verbs placed on a mob should be only related to actions that mob can perform in the first place, so most verbs at risk would be placed under /client in the first place. You have a lot of control on how you want the clone to work (at worst, if the program isn't designed too well, you could add a check for a few special verbs). You can also override mob.Logout() and the such for the clones (Logout is called before client.Del(), so there should be no problem in returning client.mob to the original one to handle logging out action). I think that, if I were to implement such a system, I would be able to contain it almost completely in the mob type for clones (it might be wiser to use an is_clone boolean, however), but maybe my viewpoint lacks the perspective of a complex game-world.
In response to Toadfish (#10)
Toadfish wrote:
(Deleted my post when trying to press edit, ha!)

Hmm, I'm not sure I understand the concerns. Let me know if I overlooked something: verbs placed on a mob should be only related to actions that mob can perform in the first place, so most verbs at risk would be placed under /client in the first place. You have a lot of control on how you want the clone to work (at worst, if the program isn't designed too well, you could add a check for a few special verbs). You can also override mob.Logout() and the such for the clones (Logout is called before client.Del(), so there should be no problem in returning client.mob to the original one to handle logging out action). I think that, if I were to implement such a system, I would be able to contain it almost completely in the mob type for clones (it might be wiser to use an is_clone boolean, however), but maybe my viewpoint lacks the perspective of a complex game-world.

Judging what the semantics of client.mob imply based on the default behaviour, a lot of built-in code makes the assumption that the client's mob is the mob that represents the player's 'avatar'. From this, controlling a clone should not change the player's avatar, as this is different from its true intent.

I'm making these claims based on how a lot of this built-in client/mob interactions and behaviours seem to work. It is true that you can override the behaviour in question, but it does not make sense to destruct and refactor current well-defined behaviour to do a task when you can create new behavior to do your particular task. This is especially true for built-in code. The intent of the client.mob setting can stay the same, but a new feature that creates interaction between the client and the mob can break your feature while still keeping the same assumption: that the client's mob is the player's avatar.

The point is that from the perspective of the client, you don't need to set 'client.mob' to anything to control it because you already have access to any client-mob interaction (such as movement, keypresses, and to a certain extent, verbs).

Generally, it should be okay when you've made the assumption in your whole project that the player's mob isn't necessarily connected to its client (ie. designing client-based interactions strictly with clients). The problem is that these assumptions are already pretty engrained in default behaviour as discussed above, and a lot of code in general tends to make the assumption that if a mob is controlled by a client, then that mob is the client's avatar.
In response to Unknown Person (#11)
As you noted, your objection is mostly philosophical. The problem is present when the game author assumes the mob is also a unique avatar. I agree with this much, but not necessarily with the assumption itself. The very existence of client.mob as a public variable implies the disconnection between a client and a mob. Philosophically, a mob is intended to serve as a "shell" or a "host" for a client, not as a direct part of it. A game that makes the assumption a mob is a unique avatar is, in my opinion, following very bad OO practices, and would benefit more from redesigning the system from the ground than building on it.

Aside from that, there is also the certain, unpleasant aesthetic tick a programmer feels when he has to add awkward hooks to client-side functionality. I think a solution that contains the clone in a single 'mob' object is a lot more elegant than a solution that has to override client commands for special, circumstance-dependant situations.

However, to be practical, I agree my suggestion has no direct benefit if the author makes the assumption you mentioned, and is looking for a solution that "builds on" the code base rather than refactoring it. I do, however, think programmers who make that assumption would have a lot more trouble in the long-term, whatever solution they use.
In response to Toadfish (#12)
Toadfish wrote:
As you noted, your objection is mostly philosophical. The problem is present when the game author assumes the mob is also a unique avatar. I agree with this much, but not necessarily with the assumption itself. The very existence of client.mob as a public variable implies the disconnection between a client and a mob. Philosophically, a mob is intended to serve as a "shell" or a "host" for a client, not as a direct part of it

It isn't philosophical. <code>client.mob</code>'s purpose is to handle the connection between the client and the mob, and the connection happens to deal with a whole lot more than just movement. <code>client.mob</code> is set when you connect to a world. If you set <code>client.mob</code>, procs like <code>Logout()</code> and <code>Login()</code> get called, different verbs are accessible (depending on what kind of mob you connected to), and both mob's keys are changed. Just from these, I can come to a fair conclusion that client.mob should handle the client-mob connection.

I don't disagree that you can use this neat feature to do what you want, it's just that you're going to have to deal with what it was meant to do, which means you're going to have edge-cases to what you're trying to use it for, which can change without the initial assumptions (the client-mob connection) changing. Trying to do something you want with a tool that wasn't supposed to do that task is a hack. Hacking isn't bad, it's the solution when you have constraints. It's just not a good idea when you actually are capable of writing your code to its requirements.

A game that makes the assumption a mob is a unique avatar is, in my opinion, following very bad OO practices, and would benefit more from redesigning the system from the ground than building on it.

User-specified convention (in this case, client.mob) has very little to do with OOP practice. It's just specification. You can do whatever you want to it, you just need to know what changing it does, and what it means when you do so.

Aside from that, there is also the certain, unpleasant aesthetic tick a programmer feels when he has to add awkward hooks to client-side functionality. I think a solution that contains the clone in a single 'mob' object is a lot more elegant than a solution that has to override client commands for special, circumstance-dependant situations.

It probably seems more elegant because you're writing less code. The fact is that someone wrote that code for a purpose, and you're re-purposing that code, and getting around the initial assumptions.

You should deal with that unpleasant aesthetic tick, it's an irrational reason to not do something. There is nothing wrong with extending behaviour of existing datums. That's the whole point of OOP. DM happens to be a language where you can override a built-in data type without subclassing it.

I do, however, think programmers who make that assumption would have a lot more trouble in the long-term, whatever solution they use.

I disagree. Using features for what they're not meant to be used for will cause more trouble in the future. Software requirements change all the time. If you're repurposing software, especially on a built-in feature, then you will end up spending more time on repurposing the tool than creating your tool with your requirements.

I'm going to end the discussion here because I think all really has been said. The point really is that you can do whatever the heck you want. But really, from a general perspective, OOP is all about extending functionality, not repurposing it. If you can't extend it, go a level higher. That said, OOP becomes something nasty when spelled backwards. ;)
In response to Unknown Person (#13)
It isn't philosophical. client.mob's purpose is to handle the connection between the client and the mob, and the connection happens to deal with a whole lot more than just movement. client.mob is set when you connect to a world. If you set client.mob, procs like Logout() and Login() get called, different verbs are accessible (depending on what kind of mob you connected to), and both mob's keys are changed. Just from these, I can come to a fair conclusion that client.mob should handle the client-mob connection.
I don't disagree that you can use this neat feature to do what you want, it's just that you're going to have to deal with what it was meant to do, which means you're going to have edge-cases to what you're trying to use it for, which can change without the initial assumptions (the client-mob connection) changing. Trying to do something you want with a tool that wasn't supposed to do that task is a hack. Hacking isn't bad, it's the solution when you have constraints. It's just not a good idea when you actually are capable of writing your code to its requirements.

Of course it's philosophical! You're discussing what you believe to be the way client.mob should be used. You believe it's supposed to be used in a certain way, but I don't agree with you. The disagreement here is about the function of client.mob; in other words, a discussion about the philosophy behind it.

User-specified convention (in this case, client.mob) has very little to do with OOP practice. It's just specification. You can do whatever you want to it, you just need to know what changing it does, and what it means when you do so.

This user-specified convention will blur the difference between client and mob, as well as these objects' roles (at least, the roles I believe is most logical to attribute to them). In that sense, yes, I'd say it will very much influence the object design of a game.

It probably seems more elegant because you're writing less code. The fact is that someone wrote that code for a purpose, and you're re-purposing that code, and getting around the initial assumptions.
You should deal with that unpleasant aesthetic tick, it's an irrational reason to not do something. There is nothing wrong with extending behaviour of existing datums. That's the whole point of OOP. DM happens to be a language where you can override a built-in data type without subclassing it.

I think you'll actually be writing /more/ code in the class case. And I also posit that you're confusing the meaning of object oriented programming with proper object oriented modelling. I find adding hooks where they shouldn't be (such as when it's highly circumstantial) - according to me, of course - a bad practice, and one that, whenever possible, should be avoided through self-sufficient objects.

I disagree. Using features for what they're not meant to be used for will cause more trouble in the future. Software requirements change all the time. If you're repurposing software, especially on a built-in feature, then you will end up spending more time on repurposing the tool than creating your tool with your requirements.

I completely agree, and I think client.mob shouldn't be used the way you propose it should be! :P

I'm going to end the discussion here because I think all really has been said. The point really is that you can do whatever the heck you want. But really, from a general perspective, OOP is all about extending functionality, not repurposing it. If you can't extend it, go a level higher. That said, OOP becomes something nasty when spelled backwards. ;)

All right. This discussion might be beyond the scope of this thread, so this is fair.