ID:1610117
 
(See the best response by Ter13.)
Code: N/A
"I don't know how to code it"


Problem description:
I need help creating a list. The list is to store KEYS. I would like to also make a verb that adds&deletes KEYS to the list. I was hoping that someone can also explain how to make the list appear as a pop-up, permitting me to select from the mobs in the world


Help really appreciated.

Best response
look up input() in the reference.
Okay, thanks. What I'm trying to do is make a Admin list that saves somewhere in my game
mob
verb
ManuallyAddGM()
owner= input("Input the GM name","Key Name")


What I wanted was for the verb to stream mobs in the world and allow me to select what player.
This what i did in an old file but I forgot what I was trying to do.

//////////////////
//Set Staff List//
//////////////////
//*****************************************//
var/list/admin= list("Alex Ovide")
//*****************************************//
////////////////////////
//Save Staff Directory//
////////////////////////
//*****************************************//
var/admin_save="Saves/Admins/admin.sav"
//*****************************************//
//////////////////////
//Staff Save Process//
//////////////////////
//*****************************************//
proc/save_admin()
if(fexists(admin_save))
fdel(admin_save)
var/savefile/s=new(admin_save)
s["admin"] >> admin
//*****************************************//
proc/save_staff()
save_admin()
A sample of what you are looking for would be something like this.

var/list/clients;
var/list/sample_list;

world {

New() {

. = ..();
clients = new list();
sample_list = new list();

}

}

Client {
New() {
. = ..();
clients.Add(src);
}

Del() {
clients.Remove(src);
if(src in sample_list)
sample_list.Remove(src);
. = ..();
}
}

proc/addToList() {
var/client/addKey = input("Add a key to sample_list") in clients;
// Authorization
sample_list.Add(addKey);
}

proc/removeFromList() {
var/client/removeKey = input("Who would you like to remove") in sample_list;
// Authorization
sample_list.Remove(removeKey);
}


This isn't failsafe, however, isn't exhaustive, and certainly isn't the best approach. I'm just explaining how the input works, really.

With the above code, you leave yourself vulnerable to adding the same client multiple times (easily fixable). You also are left vulnerable to being forced to add/remove users whenever these procedures are called. There are obvious ways around this, but a more intuitive GUI or command-line options are much more preferable.
lol I never learn C+ or C++ is there an easier way to translate all that? the "{" "}" confuses the heaven out of me
In response to Alex Ovide
Alex Ovide wrote:
lol I never learn C+ or C++ is there an easier way to translate all that? the "{" "}" confuses the heaven out of me

It's for code blocks in if statements and for loops and whatnot. It's not terribly necessary.

Really, all you need is this:
var/x = input("Input a number") as num | null
if(!isnull(x)) world << x
Thank you but I'm using names from keys. Do i still use x? you have in your statement
as num
No. My code was an example on using input(). You're gonna have to figure out how to use it for your own purposes. But I will add this. You can make lists show up as well.

var/list/Nums = list(1,2,3,4)
var/x = input("Which number?") in Nums | null
if(!isnull(X)) world << x
In response to Alex Ovide
Read up on input from the documentation. Specifically, if you are looking for an input from a list, the code is:

var/client/c = input("Choose a client") in clients // where clients is a list of clients
doProc(c) // do whatever you like with this client


The brackets are just a habit from not really doing much programming in DM, though I'm 99% sure my code would compile fine in the DM compiler; though I didn't really test it out. Brackets help you separate logic better instead of getting confused by indentation.
Now I'm slightly lost. I'm trying to create a "list" for "admin" so I can add them while I'm in the game.
var/list/admin

Seeing as I don't want to lose my list of mobs I created this.
var/admin_save="Saves/Admins/admin.sav"

The process I used to secure the save is this.
proc/save_admin()
if(fexists(admin_save))
fdel(admin_save)
var/savefile/s=new(admin_save)
s["admin"] >> admin

Then I redefined the save so that I can apply it as a verb.

proc/save_staff()
save_admin()


In response to Alex Ovide
A few issues with this:

(1) You will get runtime errors
You have define the variable but you have not initialized it. because it is not initialized, you will get a runtime error when you try to do list.Add(X) or reference the variable to a string when you try to do list += X

To initialize the variable, add "= list()"
var/list/admin = list() //  or new or new /list


(2) Do not save /mob

Do NOT save /mob. This is often the cause of "rollback bugs". If you load the list (or another variable) containing an older /mob, the current player - if logged in - will have their current /mob replaced with the older reference :(

Fix: Save client.key or client.ckey instead.

ckey would be better as it has the text lowercased so if I logged in as ghostAnime, it will not affect me since it'll look for ghostanime instead of client.key which will look for GhostAnime. The 'ghostAnime' login thing was an issue in the past, unsure but I think this may have been fixed.

If you do have variables that refer to other /mob that is not important (ex: party leader, tracker, etc.), define the variable as tmp so this variable is NOT saved. Ex:
mob/var/tmp/mob/Party_Leader
// Though it would be better to have a datum for the party stuff:

mob
var
tmp
Party // Make the party unsavable. Less bulk

Party
var/tmp
mob/Leader



(3) Hash/encrypt your admin file
Your saving system looks good but the host can easily modify your file. Hash or encrypt your admin file and verify upon each load.
Save_Savefile
...your s file stuff...
var/savefile/F = new("essential") // It's been a while since I programmed in BYOND so do not blindly copy/paste
F["salt"] << salt(s_file) // Ex: salt => "Super" + md5("salt") md5(s_file) + "Shaker" // Of course your encryption/hash should be stronger

Load_Savefile
... Load F, obtain salt of s admin file (not loaded yet)
if(!F["salt"] || F["salt"] != salt(s_file))
CRASH("Essential file is corrupted! Please contact game owner or reinstall the game!:)
shutdown()
return 0


(4) What verb?

All I see is a proc mentioned rather than a verb. No point of two procs... well, calling the same procedure.

Upon client/New() or mob/Login, verify if the person is in the admin list and add the Admin commands.


(5) Adding someone

Where is your snippet of adding someone? What you want is a list() of current CLIENTS on and, I highly recommend, the null option as well for the cancel button.

Before adding the client chosen, verify that the option is not null (which can be through the cancel key).

This can be done by checking if the client/option exists via if(choice){value exists} or checking if it is false: if(!choice){choice is false}
In response to GhostAnime
While I agree with the notion of storing the ckey's to save (it's less resource-heavy, as it's only strings), I do recommend during gameplay having a list of online admin's that do actually reference in-game administrators. The benefit to this is if there requires interaction, you want to contact someone who is actually online. The exception to this would be adding / removing.

var/list/clients;        // all clients in the world.
var/list/admins; // all admins, tied by Strings (ckey)
var/list/online_admins; // all admins online (clients)

world
New()
. = ..();
clients = new list();
admins = loadAdmins(); // function to retrieve admins from savefile
online_admins = new list();

client
New()
. = ..();
clients.Add(src);
if(ckey in admins)
online_admins.Add(src)
Del()
assert(src in clients); // sanity check, might be unnecessary in your case
clients.Remove(src);
if(src in online_admins)
online_admins.Remove(src);
. = ..();

admin
proc
addAdmin()
var/list/ckeys = new list();
for(var/client/c in clients)
if(c.ckey not in admins)
ckeys.Add(c.ckey);
var/new_admin_ckey = input("Add a new admin") in ckeys + "Cancel";
if(new_admin_ckey == "Cancel")
return;
admins.Add(new_admin_ckey);

// etc etc


This gives a better separation for administrative actions. You can quickly automate a lot more by separating these three lists, and only maintaining a savefile of list/admins.

Of course, if you want anything half-way decent, you wouldn't deal with these default datum's. You'd construct a separate datum. As well, the addAdmin() proc I gave is certainly not the best approach. It's a whipped-up example, but you will certainly run into issues with it. The first and fore-most issue is that it's not the most efficient way. The most efficient way would be to cycle through a list of un-added clients, but then you run the risk of not having a way out. You could add the 'null' option as GhostAnime suggests, but that's just ugly. You're better off rewriting the input method if you want anything truly nice.

Also, your question about the verb confused me as much as it did GhostAnime. The statement didn't make any sense.

Anyways, you've been given plenty of help in this topic. I hope you learn from it ;)
Was my list for administrative wrong?
I'm trying to understand it buto really I would like the most simplest explanation. Like 1+2=3. I am still new to coding and the snippets that I'm learning from is enough. I looked at the input() reference and was really sure to where list was being explained.