ID:179092
 
I'm trying to add a code that will automatically assign people to a party when they log in. Each person willl start in their own party and may join other players' parties if they choose to do so. I'm not very good with lists yet, and I get errors starting with the for(...) line. Is this not the correct way to cycle through the members of a party?

under login(), I have

global/var/party[] // the master party list
for(var/M in party[]) // cycles through all parties
if(party[M] = 0) // if party is not occupied
party[M] = 1 // put player into party
user.group = M // associate player with party number
break
Gakumerasara wrote:
I'm trying to add a code that will automatically assign people to a party when they log in. Each person willl start in their own party and may join other players' parties if they choose to do so. I'm not very good with lists yet, and I get errors starting with the for(...) line. Is this not the correct way to cycle through the members of a party?

under login(), I have

global/var/party[] // the master party list
for(var/M in party[]) // cycles through all parties
if(party[M] = 0) // if party is not occupied
party[M] = 1 // put player into party
user.group = M // associate player with party number

The empty brackets are largely unnecessary. Your global var can be defined as var/list/party outside of Login() (although if you have more than one party, that's actually not the best way to do it). For Login(), the for loop shouldn't use those brackets, so it should say for(var/M in party).

I would actually implement parties a little differently: I'd set up a datum to do it, like this:
party
var/list/chars

New(mob/leader)
chars=list(leader)
leader.party=src
parties+=src

Del()
parties-=src
for(var/mob/char in chars) char.party=null
..()

proc/Add(mob/char)
chars+=char
char.party=src
chars << "[char] joins the party."

proc/Remove(mob/char)
chars << "[char] leaves the party."
chars-=char
char.party=null
if(!chars.len) del(src)

proc/Size()
return chars.len

proc/GetLeader()
if(chars.len) return null
return chars[1]

var/list/parties=list() // global party list

mob
var/party/party=null

Login()
..()
var/list/l=list() // list of smallest parties
var/minchars // chars in smallest party
var/party/P
if(parties.len) // establish a baseline minimum
P=l[1]
minchars=P.Size()
// find the party with the fewest members
// if more than one, pick at random
for(P in parties)
if(P.chars.len>minchars) continue
if(P.chars.len<minchars)
minchars=P.chars.len
l=list()
l+=P
if(l.len)
// in 306 this line won't work, so use P=l[rand(1,l.len)]
P=pick(l)
P.Add(src)

Logout()
if(party) party.Remove(src)
..()

Using custom datums like this really expands your options a lot. I'm a big fan of the technique.

Lummox JR
In response to Lummox JR
I tried to integrate some of what you said with my original login() code. I kind of see what you were doing, but I know even less about datums than about lists. This is the code I had before, which is based largely on one of the demos:



world
mob = /mob/newcharacter
view = 7
turf = /turf/grass

mob/newcharacter
var/mob/PC/newchar // what the user will soon become
Login()
var/charname = input("Choose a name.","Name",src.key)
[a series of switches to determine gender and class]
[gender = "male" or "female" depending on choice]
[newchar = new /mob/(whatever class)]
newchar.gender = gender
newchar.name = charname //set the name
src.client.mob = newchar //change the player to newchar
del(src) //delete the old mob



so, if I add

mob/newcharacter
var/list/party = null

in the code somewhere, that would be like a party of 1 (or no followers), right?

all I really need is for everyone to start in their own party with the option of joining other people later

about the datum, wouldn't

mob/verb
[add, remove, whatever]

work the same as

party
proc/[whatever]

when I have to call the procs in verbs anyway?

This is all getting very confusing, but I'm trying to get it out of the way now instead of letting it come back to haunt me later.
In response to Gakumerasara
Gakumerasara wrote:
so, if I add

mob/newcharacter
var/list/party = null

in the code somewhere, that would be like a party of 1 (or no followers), right?

Well actually under my datum system it would have to be var/party/party, not a list.
If you don't use a datum here, things could get kind of messy. Somewhere you'd need a list of who's in each party, and it makes much more sense to have a different list for each party than one big global list. You'd also need a var indicating who the leader is, or where the party's list would be found. Basically you'd end up replicating all the same mechanisms but in a more spread-out and disjointed way; more chances for bugs there.

all I really need is for everyone to start in their own party with the option of joining other people later

To do that you could always add, in the login code:
new /party(src)

Since the party datum sets the mob's party var automatically, this is all you need.

about the datum, wouldn't

mob/verb
[add, remove, whatever]

work the same as

party
proc/[whatever]

when I have to call the procs in verbs anyway?

There might be other cases for removing people from the party besides just verbs: Death checks, for example, would need to alter the party list.

Putting all the verbs in the mob make sense only if the party list is controlled by the mob, or if there's a big global party list similar to the one you were using, but that's not a very robust solution. (For example, consider the problem of sending a message to everyone in the party. You'd have to search through the global list rather than using a single list for the one party.)
If just the mob has the party list, things get weirder: Does only the leader have this list, or everyone? If everyone has the same list, the lists run a strong chance of getting out of sync and causing bugs. If only the leader has the list, then everyone needs another var pointing to the leader; if anything happens to the leader so he's suddenly inaccessible (like by the mob being deleted), no one can tell who else was in the party.

This is all getting very confusing, but I'm trying to get it out of the way now instead of letting it come back to haunt me later.

I think any solution other than the datum approach (or something close to it) will definitely come back to haunt you. Such things would need more code to do the same task, with more vars set up in such a way that minor changes to seemingly unrelated parts of the code could cause the whole thing to fall apart.

Basically any time you've got an "entity" to handle, it's good to set up some kind of data structure to deal with it. When that entity is crucial to your game, then the more robust your code is, the better. A party is an entity unto itself, so it should be treated as such in the code.

Lummox JR
Gakumerasara wrote:
I'm trying to add a code that will automatically assign people to a party when they log in. Each person willl start in their own party and may join other players' parties if they choose to do so. I'm not very good with lists yet, and I get errors starting with the for(...) line. Is this not the correct way to cycle through the members of a party?

under login(), I have

global/var/party[] // the master party list
for(var/M in party[]) // cycles through all parties
if(party[M] = 0) // if party is not occupied
party[M] = 1 // put player into party
user.group = M // associate player with party number
break

I'm not sure exactly what your trying to do with this so I'll just talk about lists in general.

When you use a for loop to go through a list like this:
for(var/M in party)
it cycles through the entire list and assigns each member in the list to M, temporarily and one at a time.
Here's an example:
for(var/mob/M in party)
world << "[M] is in the party"

This would print out each member of the party that is contained in the list.
In response to Lummox JR
I've been trying to get the code you posted to work before modifying it too much. I did change a few things, but I still can't get it to work. I took out your login() code and used


mob/PC/Knight
New()
new /party(src)
[other vars, etc.]


instead. I haven't changed changed the following at all:


party
var/list/chars

New(mob/leader)
chars=list(leader)
leader.party=src
parties+=src

Del()
parties-=src
for(var/mob/char in chars) char.party=null
..()

proc/Add(mob/char)
chars+=char
char.party=src
chars << "[char] joins the party."

proc/Remove(mob/char)
chars << "[char] leaves the party."
chars-=char
char.party=null
if(!chars.len) del(src)

proc/Size()
return chars.len

proc/GetLeader()
if(chars.len) return null
return chars[1]

var/list/parties=list() // global party list

mob
var/party/party=null

Logout()
if(party) party.Remove(src)
..()



and I also added some verbs to call the procs:



mob/verb
Add(mob/char)
call (/party/proc/Add)(char)

Remove(mob/char)
call (/party/proc/Remove)(char)

Size()
call (/party/proc/Size)()

GetLeader()
call (/party/proc/GetLeader)()


When I run the game I get the following error message (for one knight trying to join another using the Add verb):


runtime error: Cannot read null.chars.
proc name: Add (/party/proc/Add)
usr: Guest (/mob/PC/Knight)
src: null
call stack:
Add(DKnight (/mob/PC/Knight))
Guest (/mob/PC/Knight): Add(Knight (/mob/PC/Knight))


Similar errors are shown when knights die in combat and the del() proc is called. Do you have any idea what could be wrong with my coding? I'm guessing that it has to do with an inability to read the lists correctly or in looking for null.chars instead of src.chars, but I really don't know.
In response to Gakumerasara
Gakumerasara wrote:
mob/verb
Add(mob/char)
call (/party/proc/Add)(char)

Remove(mob/char)
call (/party/proc/Remove)(char)

Size()
call (/party/proc/Size)()

GetLeader()
call (/party/proc/GetLeader)()

This "call" syntax is incorrect, and it's the source of your errors. Apparently it works in part, but it's working without giving it a party datum to use as src. You should change them to this:
mob/verb
Add(mob/char)
if(party)
if(char.party) char.party.Remove(char)
party.Add(char)

Remove(mob/char)
if(party && char.party==party)
party.Remove(char)

Size()
if(party) usr << "The party has [party.Size()] member\s."

GetLeader()
if(party)
var/mob/char=party.GetLeader()
usr << "[(char==src)?"You are":"[party.GetLeader()] is"] the leader of your party."

Lummox JR
In response to Lummox JR
I've been working at this for a while, trying to learn exactly how lists and datums work, and I restarted my party code. I've been working my way up in small increments, experimenting with things that I took for granted before. I made this simple code during my experiments, but I can't figure out why it won't output the names of party members within a party. If you have any idea what I'm doing wrong, please let me know. Thanks.

var/list/parties=list() // global party list

mob/var/party/party=null

party
var/list/chars

New(partyname, mob/leader)
chars=list(src)
leader.party=src
parties+=partyname

mob/verb
Create_Party()
var/partyname = input("Please choose a name for your party.","Party Name","[src.key]'s Party")
new /party(partyname, src)

List_Parties()
src << "Current Parties:"
for(var/group in parties)
src << " [group]"
for(var/members in group)
src << " [members]"


The party name is shown, but the members are not. I tried changing var/members to var/mob/members so that I could use members.key and members.name in the output, but this had the same result.
In response to Gakumerasara
You are adding the party's name to the global parties list in party's New() proc. When you loop through the parties in List_Parties(), you are then trying to look through the members of each party name. The name is text, not a list, so there are no members to loop through. In party's New() proc, add the party's src to the parties list instead. Make a proc within party to get the members of that party.

Also, mobs have a group var. You might want to avoid using that var name within mob procs so you don't confuse anything.

Suggestion: Make List_Parties() global instead of putting it in mob.