mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 02:16:05 +00:00
Minds part2 - Carn loses her mind. The way datum/mind stuff works has been changed a lot. I really can't explain everything. If you have any questions it'd just be easier if you leave a comment or ask me in coderbus. Generally, minds now represent IC characters rather than following a client around constantly. Minds can change owners, mobs, (names WIP). Technical babble: The var/current and var/original variables of the mind datum must always be of type mob/living (or null). Please do not mind.transfer_to(ghost_mob). If you want to ghost somebody use ghostize()! It will do all the technical stuff for you. mob/dead/observer/var/corpse was removed. mob/dead/observer/var/mind is now used as a reference to the last mind the player had (so respawning code has something to reference), but also because mind.current is a far more useful way of tracking a corpse. If somebody triggers a mind.transfer_to() call on your corpse, your mind will be tranfered to another mob/living or something...that will then be considered your corpse. This could allow for more interesting mind_transfers. For instance, the "raise corpse" rune ghostizes any player in the corpse to be raised and selectes a random dead player to take possesion of their character! The person possesing them will have all of their memories, objectives, etc. The poor guy who was originally the owner cannot re-enter body if there is another player in his body...but if that player is ghosted he can once again return. Exorcisms anybody? Changes to cloning and hydroponics. I will likely have to rework these later as they're hacky as hell right now. A lot of stuff is now handled by Login/Logout rather than in hundreds of different places. One such example, mind datums get their variables updated at Login and Logout. Fixed a few minor bugs. I'll update the issues manually in a bit because I literally cannot think atm. TL;DR guide: -If you want to make somebody a ghost use ghostize(). Or you will need to find a doctor to stitch your bits back on. :) -You don't have to worry about making minds. Simply doing key="carnwennan" or whatever will either: A) make a new mind and initialise it if there isn't one or B) take possession of the mind currently attached to the mob. -It's safe to transfer a mind even if a key isn't in-body (e.g. they are ghosted/admin-observing etc!) Minds have an active variable which tracks whether they are currently synced with a key. This is to avoid dragging ghosts back into their bodies when say, a wizard mind_transfers them. -Transferring a mind whilst var/active=1 will cause the following: mob.key = mind.key. So no need to do that separately (in fact you'll lag things if you do, so don't) -If you do want to initialize a mind manually, say if you don't have a client to login to the mob yet, simply do new_mob.mind_initialize(). Simple! When someody is logged into that mob they will take ownership of the mind and it will sync up. NOTE: a lot is probably broken since this is a pretty massive change. Please let me know asap (with actual info! Shouting at me, "IT BORKED HALP", doesn't help) git-svn-id: http://tgstation13.googlecode.com/svn/trunk@4342 316c924e-a436-60f5-8080-3fe189b3f50e
394 lines
12 KiB
Plaintext
394 lines
12 KiB
Plaintext
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
|
|
|
/mob/new_player
|
|
var/datum/preferences/preferences = null
|
|
var/ready = 0
|
|
var/spawning = 0//Referenced when you want to delete the new_player later on in the code.
|
|
var/totalPlayers = 0 //Player counts for the Lobby tab
|
|
var/totalPlayersReady = 0
|
|
|
|
invisibility = 101
|
|
|
|
density = 0
|
|
stat = 2
|
|
canmove = 0
|
|
|
|
anchored = 1 // don't get pushed around
|
|
|
|
verb/new_player_panel()
|
|
set src = usr
|
|
new_player_panel_proc()
|
|
|
|
|
|
proc/new_player_panel_proc()
|
|
var/user = sqlfdbklogin
|
|
var/pass = sqlfdbkpass
|
|
var/db = sqlfdbkdb
|
|
var/address = sqladdress
|
|
var/port = sqlport
|
|
|
|
var/output = "<div align='center'><B>New Player Options</B>"
|
|
output +="<hr>"
|
|
output += "<p><a href='byond://?src=\ref[src];show_preferences=1'>Setup Character</A></p>"
|
|
|
|
if(!ticker || ticker.current_state <= GAME_STATE_PREGAME)
|
|
if(!ready) output += "<p><a href='byond://?src=\ref[src];ready=1'>Declare Ready</A></p>"
|
|
else output += "<p><b>You are ready</b> (<a href='byond://?src=\ref[src];ready=2'>Cancel</A>)</p>"
|
|
|
|
else
|
|
output += "<p><a href='byond://?src=\ref[src];late_join=1'>Join Game!</A></p>"
|
|
|
|
output += "<p><a href='byond://?src=\ref[src];observe=1'>Observe</A></p>"
|
|
|
|
if(!IsGuestKey(src.key))
|
|
var/DBConnection/dbcon = new()
|
|
dbcon.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]")
|
|
|
|
if(dbcon.IsConnected())
|
|
var/isadmin = 0
|
|
if(src.client && src.client.holder)
|
|
isadmin = 1
|
|
var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_poll_question WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM erro_poll_vote WHERE ckey = \"[ckey]\")")
|
|
query.Execute()
|
|
var/newpoll = 0
|
|
while(query.NextRow())
|
|
newpoll = 1
|
|
break
|
|
|
|
if(newpoll)
|
|
output += "<p><b><a href='byond://?src=\ref[src];showpoll=1'>Show Player Polls</A> (NEW!)</b></p>"
|
|
else
|
|
output += "<p><a href='byond://?src=\ref[src];showpoll=1'>Show Player Polls</A></p>"
|
|
dbcon.Disconnect()
|
|
|
|
output += "</div>"
|
|
|
|
src << browse(output,"window=playersetup;size=210x240;can_close=0")
|
|
return
|
|
|
|
proc/Playmusic()
|
|
while(!ticker) // wait for ticker to be created
|
|
sleep(1)
|
|
|
|
var/waits = 0
|
|
var/maxwaits = 100
|
|
while(!ticker.login_music)
|
|
sleep(2)
|
|
|
|
waits++ // prevents DDoSing the server via badminery
|
|
if(waits >= maxwaits)
|
|
break
|
|
|
|
src << sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = 1) // MAD JAMS
|
|
|
|
Stat()
|
|
..()
|
|
|
|
statpanel("Lobby")
|
|
if(client.statpanel=="Lobby" && ticker)
|
|
if(ticker.hide_mode)
|
|
stat("Game Mode:", "Secret")
|
|
else
|
|
stat("Game Mode:", "[master_mode]")
|
|
|
|
if((ticker.current_state == GAME_STATE_PREGAME) && going)
|
|
stat("Time To Start:", ticker.pregame_timeleft)
|
|
if((ticker.current_state == GAME_STATE_PREGAME) && !going)
|
|
stat("Time To Start:", "DELAYED")
|
|
|
|
if(ticker.current_state == GAME_STATE_PREGAME)
|
|
stat("Players: [totalPlayers]", "Players Ready: [totalPlayersReady]")
|
|
totalPlayers = 0
|
|
totalPlayersReady = 0
|
|
for(var/mob/new_player/player in player_list)
|
|
stat("[player.key]", (player.ready)?("(Playing)"):(null))
|
|
totalPlayers++
|
|
if(player.ready)totalPlayersReady++
|
|
|
|
Topic(href, href_list[])
|
|
if(!client) return 0
|
|
|
|
if(href_list["show_preferences"])
|
|
preferences.ShowChoices(src)
|
|
return 1
|
|
|
|
if(href_list["ready"])
|
|
if(!ready)
|
|
ready = 1
|
|
else
|
|
ready = 0
|
|
|
|
if(href_list["refresh"])
|
|
src << browse(null, "window=playersetup") //closes the player setup window
|
|
new_player_panel_proc()
|
|
|
|
if(href_list["observe"])
|
|
|
|
if(alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No") == "Yes")
|
|
var/mob/dead/observer/observer = new()
|
|
|
|
spawning = 1
|
|
src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // MAD JAMS cant last forever yo
|
|
|
|
close_spawn_windows()
|
|
var/obj/O = locate("landmark*Observer-Start")
|
|
src << "\blue Now teleporting."
|
|
observer.loc = O.loc
|
|
observer.key = key
|
|
if(preferences.be_random_name)
|
|
preferences.randomize_name()
|
|
observer.name = preferences.real_name
|
|
observer.real_name = observer.name
|
|
|
|
preferences.copy_to_observer(observer)
|
|
|
|
del(src)
|
|
return 1
|
|
|
|
if(href_list["late_join"])
|
|
LateChoices()
|
|
|
|
if(href_list["SelectedJob"])
|
|
|
|
if(!enter_allowed)
|
|
usr << "\blue There is an administrative lock on entering the game!"
|
|
return
|
|
|
|
AttemptLateSpawn(href_list["SelectedJob"])
|
|
return
|
|
|
|
if(href_list["privacy_poll"])
|
|
var/user = sqlfdbklogin
|
|
var/pass = sqlfdbkpass
|
|
var/db = sqlfdbkdb
|
|
var/address = sqladdress
|
|
var/port = sqlport
|
|
|
|
var/DBConnection/dbcon = new()
|
|
|
|
dbcon.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]")
|
|
if(!dbcon.IsConnected())
|
|
return
|
|
var/voted = 0
|
|
|
|
//First check if the person has not voted yet.
|
|
var/DBQuery/query = dbcon.NewQuery("SELECT * FROM erro_privacy WHERE ckey='[src.ckey]'")
|
|
query.Execute()
|
|
while(query.NextRow())
|
|
voted = 1
|
|
break
|
|
|
|
//This is a safety switch, so only valid options pass through
|
|
var/option = "UNKNOWN"
|
|
switch(href_list["privacy_poll"])
|
|
if("signed")
|
|
option = "SIGNED"
|
|
if("anonymous")
|
|
option = "ANONYMOUS"
|
|
if("nostats")
|
|
option = "NOSTATS"
|
|
if("later")
|
|
usr << browse(null,"window=privacypoll")
|
|
return
|
|
if("abstain")
|
|
option = "ABSTAIN"
|
|
|
|
if(option == "UNKNOWN")
|
|
return
|
|
|
|
if(!voted)
|
|
var/sql = "INSERT INTO erro_privacy VALUES (null, Now(), '[src.ckey]', '[option]')"
|
|
var/DBQuery/query_insert = dbcon.NewQuery(sql)
|
|
query_insert.Execute()
|
|
usr << "<b>Thank you for your vote!</b>"
|
|
usr << browse(null,"window=privacypoll")
|
|
|
|
dbcon.Disconnect()
|
|
|
|
if(!ready && href_list["preferences"])
|
|
preferences.process_link(src, href_list)
|
|
else if(!href_list["late_join"])
|
|
new_player_panel()
|
|
|
|
if(href_list["priv_msg"])
|
|
..() //pass PM calls along to /mob/Topic
|
|
return
|
|
|
|
if(href_list["showpoll"])
|
|
handle_player_polling()
|
|
return
|
|
|
|
if(href_list["pollid"])
|
|
var/pollid = href_list["pollid"]
|
|
if(istext(pollid))
|
|
pollid = text2num(pollid)
|
|
if(isnum(pollid))
|
|
src.poll_player(pollid)
|
|
return
|
|
|
|
if(href_list["votepollid"] && href_list["voteoptionid"])
|
|
var/pollid = text2num(href_list["votepollid"])
|
|
var/optionid = text2num(href_list["voteoptionid"])
|
|
vote_on_poll(pollid, optionid)
|
|
|
|
proc/IsJobAvailable(rank)
|
|
var/datum/job/job = job_master.GetJob(rank)
|
|
if(!job) return 0
|
|
if((job.current_positions >= job.total_positions) && job.total_positions != -1) return 0
|
|
if(jobban_isbanned(src,rank)) return 0
|
|
return 1
|
|
|
|
|
|
proc/AttemptLateSpawn(rank)
|
|
if(!IsJobAvailable(rank))
|
|
src << alert("[rank] is not available. Please try another.")
|
|
return 0
|
|
|
|
var/mob/living/carbon/human/character = create_character()
|
|
var/icon/char_icon = getFlatIcon(character,0)//We're creating out own cache so it's not needed.
|
|
job_master.AssignRole(character, rank, 1)
|
|
job_master.EquipRank(character, rank, 1)
|
|
character.loc = pick(latejoin)
|
|
character.lastarea = get_area(loc)
|
|
AnnounceArrival(character, rank)
|
|
|
|
if(character.mind.assigned_role != "Cyborg")
|
|
ManifestLateSpawn(character,char_icon)
|
|
ticker.minds += character.mind//Cyborgs and AIs handle this in the transform proc. //TODO!!!!! ~Carn
|
|
else
|
|
character.Robotize()
|
|
del(src)
|
|
|
|
|
|
proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank)
|
|
if (ticker.current_state == GAME_STATE_PLAYING)
|
|
var/ailist[] = list()
|
|
for (var/mob/living/silicon/ai/A in living_mob_list)
|
|
ailist += A
|
|
if (ailist.len)
|
|
var/mob/living/silicon/ai/announcer = pick(ailist)
|
|
if(character.mind)
|
|
if((character.mind.assigned_role != "Cyborg") && (character.mind.special_role != "MODE"))
|
|
announcer.say("[character.real_name] has signed up as [rank].")
|
|
|
|
|
|
proc/ManifestLateSpawn(var/mob/living/carbon/human/H, icon/H_icon) // Attempted fix to add late joiners to various databases -- TLE
|
|
// This is basically ripped wholesale from the normal code for adding people to the databases during a fresh round
|
|
if (H.mind && (H.mind.assigned_role != "MODE"))
|
|
var/datum/data/record/G = new()
|
|
var/datum/data/record/M = new()
|
|
var/datum/data/record/S = new()
|
|
var/datum/data/record/L = new()
|
|
var/obj/item/weapon/card/id/C = H.wear_id
|
|
if (C)
|
|
G.fields["rank"] = C.assignment
|
|
else
|
|
G.fields["rank"] = "Unassigned"
|
|
G.fields["name"] = H.real_name
|
|
G.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6))
|
|
M.fields["name"] = G.fields["name"]
|
|
M.fields["id"] = G.fields["id"]
|
|
S.fields["name"] = G.fields["name"]
|
|
S.fields["id"] = G.fields["id"]
|
|
if(H.gender == FEMALE)
|
|
G.fields["sex"] = "Female"
|
|
else
|
|
G.fields["sex"] = "Male"
|
|
G.fields["age"] = text("[]", H.age)
|
|
G.fields["fingerprint"] = text("[]", md5(H.dna.uni_identity))
|
|
G.fields["p_stat"] = "Active"
|
|
G.fields["m_stat"] = "Stable"
|
|
M.fields["b_type"] = text("[]", H.b_type)
|
|
M.fields["b_dna"] = H.dna.unique_enzymes
|
|
M.fields["mi_dis"] = "None"
|
|
M.fields["mi_dis_d"] = "No minor disabilities have been declared."
|
|
M.fields["ma_dis"] = "None"
|
|
M.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
|
|
M.fields["alg"] = "None"
|
|
M.fields["alg_d"] = "No allergies have been detected in this patient."
|
|
M.fields["cdi"] = "None"
|
|
M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
|
|
M.fields["notes"] = "No notes."
|
|
S.fields["criminal"] = "None"
|
|
S.fields["mi_crim"] = "None"
|
|
S.fields["mi_crim_d"] = "No minor crime convictions."
|
|
S.fields["ma_crim"] = "None"
|
|
S.fields["ma_crim_d"] = "No major crime convictions."
|
|
S.fields["notes"] = "No notes."
|
|
|
|
//Begin locked reporting
|
|
L.fields["name"] = H.real_name
|
|
L.fields["sex"] = H.gender
|
|
L.fields["age"] = H.age
|
|
L.fields["id"] = md5("[H.real_name][H.mind.assigned_role]")
|
|
L.fields["rank"] = H.mind.assigned_role
|
|
L.fields["b_type"] = H.b_type
|
|
L.fields["b_dna"] = H.dna.unique_enzymes
|
|
L.fields["enzymes"] = H.dna.struc_enzymes
|
|
L.fields["identity"] = H.dna.uni_identity
|
|
L.fields["image"] = H_icon//What the person looks like. Naked, in this case.
|
|
//End locked reporting
|
|
|
|
data_core.general += G
|
|
data_core.medical += M
|
|
data_core.security += S
|
|
data_core.locked += L
|
|
return
|
|
|
|
|
|
proc/LateChoices()
|
|
var/mills = world.time // 1/10 of a second, not real milliseconds but whatever
|
|
//var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something
|
|
var/mins = (mills % 36000) / 600
|
|
var/hours = mills / 36000
|
|
|
|
var/dat = "<html><body><center>"
|
|
dat += "Round Duration: [round(hours)]h [round(mins)]m<br>"
|
|
|
|
if(emergency_shuttle) //In case Nanotrasen decides reposess CentComm's shuttles.
|
|
if(emergency_shuttle.direction == 2) //Shuttle is going to centcomm, not recalled
|
|
dat += "<font color='red'><b>The station has been evacuated.</b></font><br>"
|
|
if(emergency_shuttle.direction == 1 && emergency_shuttle.timeleft() < 300) //Shuttle is past the point of no recall
|
|
dat += "<font color='red'>The station is currently undergoing evacuation procedures.</font><br>"
|
|
|
|
dat += "Choose from the following open positions:<br>"
|
|
for(var/datum/job/job in job_master.occupations)
|
|
if(job && IsJobAvailable(job.title))
|
|
dat += "<a href='byond://?src=\ref[src];SelectedJob=[job.title]'>[job.title] ([job.current_positions])</a><br>"
|
|
|
|
dat += "</center>"
|
|
src << browse(dat, "window=latechoices;size=300x640;can_close=1")
|
|
|
|
|
|
proc/create_character()
|
|
spawning = 1
|
|
var/mob/living/carbon/human/new_character = new(loc)
|
|
new_character.lastarea = get_area(loc)
|
|
|
|
close_spawn_windows()
|
|
|
|
if(ticker.random_players)
|
|
new_character.gender = pick(MALE, FEMALE)
|
|
preferences.randomize_name()
|
|
preferences.randomize_appearance_for(new_character)
|
|
else
|
|
preferences.copy_to(new_character)
|
|
|
|
src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // MAD JAMS cant last forever yo
|
|
|
|
new_character.dna.ready_dna(new_character)
|
|
new_character.dna.b_type = preferences.b_type
|
|
if(mind)
|
|
mind.transfer_to(new_character)
|
|
mind.original = new_character
|
|
return new_character
|
|
|
|
|
|
Move()
|
|
return 0
|
|
|
|
|
|
proc/close_spawn_windows()
|
|
src << browse(null, "window=latechoices") //closes late choices window
|
|
src << browse(null, "window=playersetup") //closes the player setup window
|