ID:2389013
 
(See the best response by Maximus_Alex2003.)
Code:
proc/Check_Objs(mob/M,deck,name)

var/list/tmpdeck[]=new()
var/kill = 0
var/list/kill_cards = list()

for(var/A in deck)

if(A in typesof(/obj/cards))

var/obj/cards/C = new A

tmpdeck += A

del C

else
kill ++
kill_cards += A

if(kill)
M<<{"<font color=#670000><b>Please check the Deck '[name]' for the folowing [kill] missing card\s.</b></font>"}
M<<"DEBUG: Bad Card Pile Size - [kill_cards.len]"
var/kill_count = 0

while(kill_count < kill_cards.len)

kill_count++
var/card_type_path = "[kill_cards[kill_count]]"
M<<"DEBUG: Card Type Path - [card_type_path]"
card_type_path = dd_replacetextUD(card_type_path,"obj/cards","")
card_type_path = dd_replacetextUD(card_type_path,"/monster/","<b>Monster Card - Set: </b>")
card_type_path = dd_replacetextUD(card_type_path,"/spell/","<b>Spell Card - Set: </b>")
card_type_path = dd_replacetextUD(card_type_path,"/trap/","<b>Trap Card - Set: </b>")
card_type_path = dd_replacetextUD(card_type_path,"/"," <b>- Card ID:</b> ")

M<<{"<font color=#ceafaf>[card_type_path]</font>"}

return tmpdeck


Problem description:

So I won't really go too much in to detail about why this is needed, but the short story is that I occasionally have to remove an obj from the game or change its obj path.

The players have decks of cards in their save file. These decks are lists and the cards are objects. When I remove a card from the game, or have to change its path, the deck has to be updated since the game checks deck's card counts and loads objects from the list, so it's important that there's no bad objects in a player's deck before they try to play or it will cause major issues later in the game.

This proc here receives each deck on login, creates a second list, goes through each card in the initial deck, and if it's a valid card, adds it to the new deck. At the end, that corrected deck replaces the user's original deck so that the removed cards are no longer a part of it.

The issue is that sometimes players can't remember every card they have in their deck and cant figure out which card is missing without asking. I do provide update notes and make sure to include this information any time this happens, but occasionally I have to change multiple cards at once which makes it more difficult.

What I'm TRYING to do with this code here is to get the bad card's obj path as a string, and then manipulate it in to an output to try and help the users a bit.

A typical obj path for a card in my game would look like...

obj/cards/monster/HA07/EN020

in the code im using a proc... dd_replacetextUD()

which is a case sensitive text replacement proc...
dd_replacetextUD(STRING,Term to look for,Replacement Term)

I'm trying to do with this code is take that line, turn it into a string...

"obj/cards/monster/HA07/EN020"

replace the "obj/cards" portion with nothing, ""

"/monster/HA07/EN020"

replace the "/monster/" or "/spell/" or "/trap/" portion with "Monster Card - Set: "

"Monster Card - Set: HA07/EN020"

replace the final "/" with " - Card ID: "

"Monster Card - Set: HA07 - Card ID: EN020"


Which is the best I can do but it should be enough for the players.

However I can't seem to retrieve the path of the bad obj. It's obviously readable since I get errors off the proc on login.

Warning: type read from file (/obj/cards/monster/HA07/EN020) is not defined

I've tried a few different ways of getting the output but I cant seem to figure it out.
Don't save the actual objects to a savefile. Save a reference and then load the objects in runtime. As in, save an ID tag (number or text) for each card and when they load their savefile grab the ID tags and load their decks from there, more than likely using an associative list. If an ID tag no longer exists in the game, delete the ID tag from their savefile and skip trying to load that specific card and continue.
Im not being clear enough I guess.

This code works fine for what it's trying to accomplish, it strips the bad objs from the decks just fine. This isn't new code.

The new code I'm trying to work on is the output for the players.

I'm not trying to improve the save system, because adding an ID tag for the cards in the game would mean going through 13000 or so objs and adding those tags which I'm not prepared to do at the moment. It's not my original coding, I took over after the previous owner quit.

I just need to get an output out of the bad obj in some way.
        while(kill_count < kill_cards.len)

kill_count++
var/card_type_path = "[kill_cards[kill_count]]"

How do I actually get an output of any kind for that card_type_path string.

I'm getting an error in dream daemon which is...

Warning: type read from file (/obj/cards/monster/HA07/EN020) is not defined

so the game knows the bad obj type. So how do I get a variable to return that obj type?
Best response
I'm recommended to you to avoid saving actual /objs and use a different approach. This will save you a bunch of headaches now and in the future, especially when you start adding more complex features to your project, in case an /obj doesn't save properly to the save-file, in case a save-file becomes corrupt, and in case you don't want abnormally large save-files.

Your warning isn't telling you that the game knows the bad obj type, your warning is telling you the game doesn't know what that obj type is. As in, it doesn't exist in the game, it only exists in the save-file.

As far as your current issue, which again I highly recommend not going that route but...

I think you're looking for something like this:
proc
checkCard(var/obj/TARGET)
var/TYPE, SET, CARD, POSITION = 12, TEXT = "[TARGET.type]"
TYPE = "[copytext(TEXT, POSITION, findtext(TEXT, "/", POSITION, 0))]"
POSITION = 12+length(TYPE)+1
SET = "[copytext(TEXT, POSITION, findtext(TEXT, "/", POSITION, 0))]"
POSITION = 12+(length(TYPE)+length(SET))+2
CARD = "[copytext(TEXT, POSITION, findtext(TEXT, "/", POSITION, 0))]"
return list("TYPE" = TYPE, "SET" = SET, "CARD" = CARD)


That will return a list. So you can do something like:
var/list/CARD_DETAIL = checkCard(CARD)
world << "Type = [CARD_DETAIL["TYPE"]], Set = [CARD_DETAIL["SET"]], Card = [CARD_DETAIL["CARD"]]"


Me personally, I would ditch the whole hard-coded cards to begin with and make a system that will take information you give it, an image you give it, and it'll produce a config file for each individual card and save that within a folder based on the set, then based on the type.
So you would have a MONSTER folder and then it'll have your SETS folders and then in that folder will have your config file named to the card name/ID and that config file gives you the card information.
Then via runtime, you would use that information to do your calculations and data, instead of having your 13,000+ /objs. I could only imagine it's much easier on the system and a far smaller source file/resource file plus you would only use a much smaller fraction of code. You can then ban/add cards via run-time. Like, you wouldn't have to restart the server and update just to add a single card. You would just give the host the additional config file and card image.
Plus if this is a YuGiOh based game or another popular card game you wouldn't have to manually input the information to begin with. There's many many many databases online you can automatically pull information and images off of.
You're telling me to essentially recode the entire game. I didn't make this game. I'm maintaining it in the place of the original creator so the game doesn't completely shut down.

You're fixating on not liking the save system, and while I do understand that it is not ideal, that is not what I asked for help with.

I didn't make the card database. I didn't make the save system. I'm updating the database as needed, adding new content when I'm able to. I'm not about to recode a game that's been around for 15 or so years.

I am aware it doesn't know what that obj type is. That is very obvious by the error and the fact that the obj type doesn't exist. I don't want it to tell me what that obj type is. I just want it to tell me the obj type. But if I try to use X.type on it, I get a runtime error saying it cant read null.type

And just like with the code you provided above, I get the same issue.

runtime error: Cannot read null.type
Well, I mean, you're trying to get wine out of a boot.
The game has no ideal what that /obj is. At all. You're trying to give it data to read from, and the game can't reference what that data is, so it's telling you, "Look, I can see you want me to read this data, but I don't know what that data is." Which basically means your savefile is technically corrupt and should be erased.

You have to keep every /obj you make and just whitelist cards in the game, or redo the code. Trust me, I completely understand about not wanting to reprogram a major system in a project that isn't even mine.


Edit:
There's only one possible way I can see how to fix your current system. You would have to convert the save-file deck list into plain text, then scrub through the whole entire deck list text recording any /obj paths, then check if that /obj path returns a real istype() or not. If it doesn't, you have your text string to find Type, Set, Card.
Well in the coding i provided above, it already uses istype() to sort out the good obj. The kill_cards list in the code is nothing but bad type paths.

Converting the entire list in to plain text is basically exactly what I'm trying to do here.

I, unfortunately, don't know how to go about doing that.
http://www.byond.com/developer/Tafe/MSTK

Something along those lines should give you a good ideal.
Ok that's not what I'm looking for at all.

I want to convert a list in to a string. Not export the user's save file into a flat file.