Major UT Overhaul (#16544)

* Removes old UT definition files (drone/travis)
* Adds concurrency definitions to the workflows
* Changes our workflows to be more in line with what /tg does
* Adds a workflow to build/commit TGUI
* Adds a workflow to build/commit changelogs

Add python version to dependencies.sh
Fix dme errors
Removes a bunch of not included files
Cache Opendream and add directory to check_grep.py

Co-authored-by: Werner <Arrow768@users.noreply.github.com>
This commit is contained in:
Werner
2023-06-27 16:44:16 +02:00
committed by GitHub
co-authored by Werner
parent 1e0c7d8dd2
commit 3742231bc2
205 changed files with 1433 additions and 7692 deletions
+4
View File
@@ -104,3 +104,7 @@
/datum/alarm_handler/proc/notify_listeners(var/alarm, var/was_raised)
for(var/listener in listeners)
call(listener, listeners[listener])(src, alarm, was_raised)
#undef ALARM_RAISED
#undef ALARM_CLEARED
-186
View File
@@ -1,186 +0,0 @@
//citizenship defines
#define CITIZENSHIP_BIESEL "Republic of Biesel"
#define CITIZENSHIP_SOL "Sol Alliance"
#define CITIZENSHIP_COALITION "Coalition of Colonies"
#define CITIZENSHIP_ELYRA "Republic of Elyra"
#define CITIZENSHIP_ERIDANI "Eridani Federation"
#define CITIZENSHIP_DOMINIA "Empire of Dominia"
#define CITIZENSHIP_IZWESKI "Izweski Hegemony"
#define CITIZENSHIP_NRALAKK "Nralakk Federation"
#define CITIZENSHIP_EUM "Co-Operative Territories of EUM"
#define CITIZENSHIP_PRA "People's Republic of Adhomai"
#define CITIZENSHIP_DPRA "Democratic People's Republic of Adhomai"
#define CITIZENSHIP_NKA "New Kingdom of Adhomai"
#define CITIZENSHIP_FREE_COUNCIL "Free Tajaran Council"
#define CITIZENSHIP_ZORA "Zo'ra Hive"
#define CITIZENSHIP_KLAX "K'lax Hive"
#define CITIZENSHIP_CTHUR "C'thur Hive"
#define CITIZENSHIP_NONE "None"
#define CITIZENSHIP_GOLDEN "Golden Deep"
//religion defines
#define RELIGION_NONE "None"
#define RELIGION_OTHER "Other"
#define RELIGION_CHRISTIANITY "Christianity"
#define RELIGION_ISLAM "Islam"
#define RELIGION_JUDAISM "Judaism"
#define RELIGION_HINDU "Hinduism"
#define RELIGION_BUDDHISM "Buddhism"
#define RELIGION_SHINTO "Shinto"
#define RELIGION_MOROZ "Moroz Holy Tribunal"
#define RELIGION_TRINARY "Trinary Perfection"
#define RELIGION_SCARAB "Scarab Folk Beliefs"
#define RELIGION_TAOISM "Taoism"
#define RELIGION_LUCEISM "Luceism"
#define RELIGION_SIKHISM "Sikhism"
#define RELIGION_STOLITISM "Vysokan Stolitism"
#define RELIGION_THAKH "Th'akh"
#define RELIGION_SKAKH "Sk'akh"
#define RELIGION_AUTAKH "Aut'akh"
#define RELIGION_SIAKH "Si'akh"
#define RELIGION_QEBLAK "Qeblak"
#define RELIGION_WEISHII "Weishii"
#define RELIGION_SUURKA "Suur'ka"
#define RELIGION_KIRGUL "Kir'gul"
#define RELIGION_TWINSUNS "S'rendarr and Messa"
#define RELIGION_MATAKE "Ma'ta'ke"
#define RELIGION_RASKARA "Raskariim"
#define RELIGION_HIVEPANTHEON "Hive Pantheon"
#define RELIGION_PREIMMINENNCE "Preimminennce"
#define RELIGION_PILOTDREAM "Pilot Dream"
#define RELIGION_ETERNAL "The Eternal"
#define RELIGION_KSSHR "Ksshr"
#define RELIGION_SHRKH "Shrkh"
#define RELIGION_MADA "Maraka"
#define RELIGION_GLEANERS "Lights Accord"
//accent defines
#define ACCENT_CETI "Biesellite"
#define ACCENT_COC "Frontiersfolk"
#define ACCENT_ELYRA "Elyran"
#define ACCENT_ERIDANI "Eridanian"
#define ACCENT_ERIDANIREINSTATED "Reinstated Dreg"
#define ACCENT_ERIDANIDREG "Eridanian Dreg"
#define ACCENT_SOL "Solarian"
#define ACCENT_SCARAB "Scarab Fleets"
#define ACCENT_SILVERSUN_ORIGINAL "Silversun Original"
#define ACCENT_SILVERSUN_EXPATRIATE "Silversun Expatriate"
#define ACCENT_PHONG "New Hai Phongese"
#define ACCENT_MARTIAN "Martian"
#define ACCENT_KONYAN "Konyanger"
#define ACCENT_LUNA "Lunan"
#define ACCENT_GIBSON_OVAN "New Gibson Ovanstad"
#define ACCENT_GIBSON_UNDIR "New Gibson Undirstad"
#define ACCENT_HIMEO "Himean"
#define ACCENT_VYSOKA "Vysokan"
#define ACCENT_VENUS "Venusian Cytherean"
#define ACCENT_VENUSJIN "Venusian Jintarian"
#define ACCENT_DOMINIA_HIGH "High Morozi"
#define ACCENT_DOMINIA_VULGAR "Vulgar Morozi"
#define ACCENT_DOMINIA_FRONTIER "Imperial Frontier"
#define ACCENT_DOMINIA_NOVIJADRAN "Novi Jadranic"
#define ACCENT_DOMINIA_LYODII "Lyodii"
#define ACCENT_JUPITER "Jovian"
#define ACCENT_CALLISTO "Callistean"
#define ACCENT_EUROPA "Europan"
#define ACCENT_EARTH "Earther"
#define ACCENT_NCF "Non-Coalition Frontier"
#define ACCENT_FISANDUH "Fisanduhian"
#define ACCENT_GADPATHUR "Gadpathurian"
#define ACCENT_PLUTO "Plutonian"
#define ACCENT_ASSUNZIONE "Assunzionii"
#define ACCENT_VISEGRAD "Visegradi"
#define ACCENT_VALKYRIE "Valkyrian"
#define ACCENT_MICTLAN "Mictlanian"
#define ACCENT_PERSEPOLIS "Persepolis"
#define ACCENT_MEDINA "Medina"
#define ACCENT_AEMAQ "Aemaq"
#define ACCENT_NEWSUEZ "New Suez"
#define ACCENT_DAMASCUS "Damascus II"
#define ACCENT_ANTILLIA "Port Antillia"
#define ACCENT_XANU "Xanu"
#define ACCENT_SANCOLETTE "San Colette"
#define ACCENT_BURZSIA "Burzsia"
#define ACCENT_REPUBICLANSIIK "Republican Siik'maas"
#define ACCENT_NAZIRASIIK "Nazira Siik'maas"
#define ACCENT_CREVAN "Crevan Creole"
#define ACCENT_DASNRRASIIK "Das'nrra Siik'maas"
#define ACCENT_HIGHHARRSIIK "High-Harr'masir Siik'maas"
#define ACCENT_LOWHARRSIIK "Lower-Harr'masir Siik'maas"
#define ACCENT_AMOHDASIIK "Amohdan Siik'maas"
#define ACCENT_RURALDELVAHHI "Rural Delvahhi"
#define ACCENT_NOMADDELVAHHI "Nomadic Delvahhi"
#define ACCENT_OLDYASSA "Old Ya'ssa"
#define ACCENT_NEWYASSA "New Ya'ssa"
#define ACCENT_NORTHRASNRR "Northern Ras'nrr Siik'maas"
#define ACCENT_DINAKK "Din'akk Mountains Siik'maas"
#define ACCENT_HARRNRRI "Harr'nrri Siik'mas"
#define ACCENT_ZARRJIRI "Zarr'jiri Siik'mas"
#define ACCENT_HEGEMON_NOBLE "Noble Hegemonic"
#define ACCENT_HEGEMON_PEASANT "Peasant Hegemonic"
#define ACCENT_TRAD_NOBLE "Noble Traditional"
#define ACCENT_TRAD_PEASANT "Peasant Traditional"
#define ACCENT_WASTELAND "Deep Wastelander"
#define ACCENT_AUTAKH "Aut'akh Dialect"
#define ACCENT_QUEENDOM "Queendom Dialect"
#define ACCENT_TZA_PEASANT "Tza Prairie Peasant"
#define ACCENT_TZA_NOBLE "Tza Prairie Noble"
#define ACCENT_SOUTHLANDS_PEASANT "Southlands Peasant"
#define ACCENT_SOUTHLANDS_NOBLE "Southlands Noble"
#define ACCENT_BROKEN_PEASANT "Broken Coalition Peasant"
#define ACCENT_BROKEN_NOBLE "Broken Coalition Noble"
#define ACCENT_UNATHI_SPACER "Spacer"
#define ACCENT_HAZANA "Hazana"
#define ACCENT_TORN "Torn Cities"
#define ACCENT_SKRELL "Standard Nral'Malic"
#define ACCENT_HOMEWORLD "Qerrbalak"
#define ACCENT_QERRMALIC "Qerr'Malic"
#define ACCENT_ALIOSE "Aliose"
#define ACCENT_AWEIJI "Aweiji"
#define ACCENT_TRAVERSE "Traverse"
#define ACCENT_GENNER "Generational Ship"
#define ACCENT_SKRELLSOL "Solarian Skrell Standard"
#define ACCENT_SKRELLCOC "Coalition Skrell Standard"
#define ACCENT_SKRELLCETI "Biesellite Skrell Standard"
#define ACCENT_SKRELLEUM "Nral'Daaq"
#define ACCENT_SROM "Inner Voice"
#define ACCENT_TATTUQIG "Tattuqig"
#define ACCENT_ROOTSONG "Rootsong"
#define ACCENT_VOIDSONG "Voidsong"
#define ACCENT_ANCIENTSONG "Ancientsong"
#define ACCENT_CRIMSONSONG "Crimsonsong"
#define ACCENT_IRONSONG "Ironsong"
#define ACCENT_SANDSONG "Sandsong"
#define ACCENT_WASTESONG "Wastesong"
#define ACCENT_WAVESONG "Wavesong"
#define ACCENT_SUNKENSONG "Sunkensong"
#define ACCENT_STARSONG "Starsong"
#define ACCENT_TTS "Text-to-Speech"
#define ACCENT_BLUESPACE "Bluespace"
#define ACCENT_ZORA "Zo'rane"
#define ACCENT_KLAX "K'laxane"
#define ACCENT_CTHUR "C'thuric"
#define ACCENT_LIIDRA "Lii'draic"
#define ACCENTS_ALL_IPC_SOL list(ACCENT_SOL, ACCENT_EARTH, ACCENT_SILVERSUN_ORIGINAL, ACCENT_SILVERSUN_EXPATRIATE, ACCENT_VENUS, ACCENT_VENUSJIN, ACCENT_MARTIAN, ACCENT_JUPITER, ACCENT_CALLISTO, ACCENT_EUROPA, ACCENT_PHONG, ACCENT_ERIDANI, ACCENT_PLUTO, ACCENT_VISEGRAD, ACCENT_MICTLAN, ACCENT_KONYAN, ACCENT_LUNA, ACCENT_SANCOLETTE, ACCENT_TTS)
#define ACCENTS_ALL_IPC list(ACCENT_CETI, ACCENT_TTS, ACCENT_XANU, ACCENT_COC, ACCENT_ELYRA, ACCENT_ERIDANI, ACCENT_ERIDANIDREG, ACCENT_ERIDANIREINSTATED, ACCENT_SOL, ACCENT_SILVERSUN_EXPATRIATE, ACCENT_SILVERSUN_ORIGINAL, ACCENT_PHONG, ACCENT_MARTIAN, ACCENT_KONYAN, ACCENT_LUNA, ACCENT_GIBSON_OVAN, ACCENT_GIBSON_UNDIR, ACCENT_HIMEO, ACCENT_VYSOKA, ACCENT_VENUS, ACCENT_VENUSJIN, ACCENT_JUPITER, ACCENT_CALLISTO, ACCENT_EUROPA, ACCENT_EARTH, ACCENT_NCF, ACCENT_PLUTO, ACCENT_ASSUNZIONE, ACCENT_VISEGRAD, ACCENT_SANCOLETTE, ACCENT_VALKYRIE, ACCENT_MICTLAN, ACCENT_PERSEPOLIS, ACCENT_MEDINA, ACCENT_NEWSUEZ, ACCENT_AEMAQ, ACCENT_DAMASCUS)
#define RELIGIONS_ALL_IPC list(RELIGION_NONE, RELIGION_CHRISTIANITY, RELIGION_ISLAM, RELIGION_BUDDHISM, RELIGION_HINDU, RELIGION_TAOISM, RELIGION_JUDAISM, RELIGION_OTHER, RELIGION_TRINARY, RELIGION_SCARAB, RELIGION_LUCEISM, RELIGION_SHINTO)
@@ -1,7 +1,3 @@
#define RELIGIONS_BIESEL list(RELIGION_NONE, RELIGION_CHRISTIANITY, RELIGION_ISLAM, RELIGION_BUDDHISM, RELIGION_SHINTO, RELIGION_HINDU, RELIGION_TAOISM, RELIGION_JUDAISM, RELIGION_SIKHISM, RELIGION_OTHER, RELIGION_TRINARY)
#define CITIZENSHIPS_BIESEL list(CITIZENSHIP_BIESEL, CITIZENSHIP_ERIDANI, CITIZENSHIP_COALITION)
/singleton/origin_item/culture/biesellite
name = "Biesellite"
desc = "Relatively new compared to other cultures across the Orion Spur, the Biesellite culture was forged from the fire borne by its independence. Since its inception, it has continued to evolve, especially with the recent expansion of the Republic of Biesel into the Solarian Alliance's Outer Ring after its abandonment during the collapse. Despite its recent acquisition, the Corporate Reconstruction Zone as it is now known has begun adjusting and blending their own cultures into the Biesellite way of life, those not bending the knee and aligning are often bastions of insurgency and unrest."
@@ -1,7 +1,3 @@
#define RELIGIONS_COALITION list(RELIGION_NONE, RELIGION_CHRISTIANITY, RELIGION_ISLAM, RELIGION_BUDDHISM, RELIGION_SHINTO, RELIGION_HINDU, RELIGION_TAOISM, RELIGION_JUDAISM, RELIGION_SIKHISM, RELIGION_OTHER, RELIGION_TRINARY)
#define RELIGIONS_COALITION_ALL list(RELIGION_NONE, RELIGION_CHRISTIANITY, RELIGION_ISLAM, RELIGION_BUDDHISM, RELIGION_SHINTO, RELIGION_HINDU, RELIGION_TAOISM, RELIGION_JUDAISM, RELIGION_SIKHISM, RELIGION_OTHER, RELIGION_TRINARY, RELIGION_SCARAB, RELIGION_MOROZ)
#define CITIZENSHIPS_COALITION list(CITIZENSHIP_COALITION, CITIZENSHIP_BIESEL)
/singleton/origin_item/culture/coalition
name = "Coalition of Colonies"
desc = "The Coalition of Colonies was born out of the fires of the Interstellar War, the bloodiest war humanity has seen since its dawn as a species. The majority of its citizens prize their freedom above all else, which has led to problems with governance for the Coalition: to this day, it remains a very decentralized and fragmented entity that can only be brought together as a unified front in moments of extreme crisis. But with the recent growth of the Republic of Biesel, retreat of the Solarian Alliance, and an increasingly militaristic Empire of Dominia, perhaps this matter shall change in the years to come."
@@ -1,5 +1,3 @@
#define CITIZENSHIPS_DOMINIA list(CITIZENSHIP_DOMINIA, CITIZENSHIP_COALITION, CITIZENSHIP_BIESEL)
/singleton/origin_item/culture/dominia
name = "Empire of Dominia"
desc = "The Empire of Dominia (often simply referred to as \"the Empire\") is an autocratic monarchy that is heavily influenced by its state religion, the Moroz Holy Tribunal, which is often regarded as an offshoot of old Earth faiths. Imperial society is sharply divided between Morozians, which are themselves divided between noble Primaries and commoner Secondaries, and Ma'zals, which make up the population of its conquered worlds. Militaristic and expansionist, the Empire has been increasingly brought into conflict with its neighbors: the Serene Republic of Elyra and Coalition of Colonies. Dominians are often stereotyped as militant, religious, and egotistical."
@@ -1,5 +1,3 @@
#define RELIGIONS_ELYRA list(RELIGION_NONE, RELIGION_CHRISTIANITY, RELIGION_ISLAM, RELIGION_SHINTO, RELIGION_BUDDHISM, RELIGION_HINDU, RELIGION_TAOISM, RELIGION_JUDAISM, RELIGION_SIKHISM, RELIGION_OTHER)
/singleton/origin_item/culture/elyran
name = "Serene Republic of Elyra"
desc = "A rich and prosperous nation, the Serene Republic of Elyra is one of the few locations in the Orion Spur where phoron can be found. This phoron has made the Republic extremely wealthy and has given them a technological edge over much of the Spur. Highly-controlled customs and harsh immigration requirements have kept much of Elyra isolated from the broader Spur, and have led to the growth of a large population of \"Non-Citizen Persons,\" that reside in the Republic. Recent attacks by the Lii'dra Hive of the vaurca have led to the Republic becoming increasingly militarized."
@@ -1,6 +1,3 @@
#define RELIGIONS_SOLARIAN list(RELIGION_NONE, RELIGION_CHRISTIANITY, RELIGION_ISLAM, RELIGION_SHINTO, RELIGION_BUDDHISM, RELIGION_HINDU, RELIGION_TAOISM, RELIGION_JUDAISM, RELIGION_SIKHISM, RELIGION_OTHER, RELIGION_TRINARY)
#define CITIZENSHIPS_SOLARIAN list(CITIZENSHIP_SOL, CITIZENSHIP_BIESEL, CITIZENSHIP_ERIDANI, CITIZENSHIP_COALITION)
/singleton/origin_item/culture/solarian
name = "Solarian"
desc = "Despite the loss of much of its territory during the Solarian Collapse of 2463, most of those that fall under the general umbrella of Solarian culture are citizens or belong to statelets affiliated with the Alliance of Sovereign Solarian Nations (ASSN). By and large, Solarians are generally perceived as xenophobic, nationalistic, and militarist. Non-humans, aside from Skrell, are generally rare on Solarian worlds, and many that do reside on them are treated as second-class citizens at best."
@@ -1,5 +1,3 @@
/singleton/origin_item/culture/ipc_tau_ceti
name = "Tau Ceti"
desc = "Tau Ceti serves as a hotbed for IPC and synthetics in general, with their treatment and status being a contentious issue within the Republic. On average, IPC within the system are programmed or exposed to influences that place value on their status as individuals and encourage them to seek freedom and citizenship in life. This focus on freedom is however carefully tailored by megacorporate influence, with many synthetics being directly owned or in indentured servitude."
@@ -12,4 +10,4 @@
desc = "IPC have had a strong presence on Biesel, a place viewed by many as a beacon of hope and freedom for all species. IPC have been granted rights to self ownership and even citizenship, complete with property and a bid in the corporate job market. However, a great number remain in impoverished conditions in the slums of District 14 of Mendell City, while the majority of synthetics are still owned under conditions similar to those of the Alliance. New Gibson similarly hosts a number of IPC as a point of entry into the wider Tau Ceti system and the Republic at large. While the cold weather may provide for a comfortable stay, the negative attitude of the human population towards synthetics has forced many to adopt a more closed and stoic outlook, tending to keep to themselves."
possible_accents = ACCENTS_ALL_IPC
possible_citizenships = list(CITIZENSHIP_BIESEL, CITIZENSHIP_COALITION, CITIZENSHIP_NONE)
possible_religions = RELIGIONS_ALL_IPC
possible_religions = RELIGIONS_ALL_IPC
@@ -1,6 +1,3 @@
#define CITIZENSHIPS_NRALAKK list(CITIZENSHIP_NRALAKK, CITIZENSHIP_EUM)
#define RELIGIONS_NRALAKK list(RELIGION_QEBLAK, RELIGION_WEISHII, RELIGION_SUURKA, RELIGION_KIRGUL, RELIGION_OTHER, RELIGION_NONE)
/singleton/origin_item/culture/federation
name = "Federation Skrell"
desc = "The Nralakk Federation was first formed in 900 CE to unite the Skrell diaspora on Qerrbalak and its initial colonies, and formed again in 2245 CE with the disappearance of Glorsh-Omega. The Federation throughout the centuries has always had the main goal of uplifting the Skrell species as a whole, resulting in a culture that places importance on family, success, and working as a collective for the betterment of Skrellkind."
@@ -1,6 +1,3 @@
#define RELIGIONS_ADHOMAI list(RELIGION_TWINSUNS, RELIGION_MATAKE, RELIGION_RASKARA, RELIGION_NONE, RELIGION_OTHER)
#define CITIZENSHIPS_ADHOMAI list(CITIZENSHIP_PRA, CITIZENSHIP_DPRA, CITIZENSHIP_NKA)
/singleton/origin_item/culture/adhomian
name = "Adhomian"
desc = "Adhomai is the most important planet culturally for the Tajara species. Due to its relatively recent discovery, all Tajara have some kind of connection to the homeworld. Adhomai is currently divided between three competing nations. Besides the national divide, regional and ethnic divisions still exist."
@@ -174,4 +171,4 @@
desc = "Despite all efforts by the revolutionaries to destroy the Njarir'Akhran nobility during the First Revolution, some of its members survived. These remnants still cling, to varying degrees, to the Pre-Contact traditions; a culture once infamous for its opulence and stratification. The Pre-Contact Nobility is faded to oblivion as its member succumbs to old age and the New Kingdom diverges to its own path. However, its influence is still felt in the Royalist project."
possible_accents = list(ACCENT_OLDYASSA)
possible_citizenships = CITIZENSHIPS_ADHOMAI
possible_religions = RELIGIONS_ADHOMAI
possible_religions = RELIGIONS_ADHOMAI
-41
View File
@@ -1,41 +0,0 @@
/datum/bounty/item/mech/New()
..()
description = "Upper management has requested one [name] mech be sent as soon as possible. Ship it to receive a large payment."
/datum/bounty/item/mech/ship(obj/O)
if(!applies_to(O))
return
if(istype(O, /obj/mecha))
var/obj/mecha/M = O
M.wreckage = null // So the mech doesn't explode.
..()
/datum/bounty/item/mech/mark_high_priority(scale_reward)
return ..(max(scale_reward * 0.7, 1.2))
/datum/bounty/item/mech/ripley
name = "APLU \"Ripley\""
reward = 13000
wanted_types = list(/obj/mecha/working/ripley)
/datum/bounty/item/mech/odysseus
name = "Odysseus"
reward = 11000
wanted_types = list(/obj/mecha/medical/odysseus)
/datum/bounty/item/mech/gygax
name = "Gygax"
reward = 28000
wanted_types = list(/obj/mecha/combat/gygax)
/datum/bounty/item/mech/durand
name = "Durand"
reward = 20000
wanted_types = list(/obj/mecha/combat/durand)
/*
/datum/bounty/item/mech/phazon
name = "Phazon"
reward = 50000
wanted_types = list(/obj/mecha/combat/phazon)
*/
+8
View File
@@ -225,3 +225,11 @@
if(B.claimed)
++count
return count
#undef BOUNTY_MIN
#undef BOUNTY_MAX
#undef BOUNTY_NUM_LOW
#undef BOUNTY_NUM_MED
#undef BOUNTY_NUM_HIGH
-78
View File
@@ -1,78 +0,0 @@
// Approved manifest.
// +200 credits flat.
/datum/export/manifest_correct
cost = 200
k_elasticity = 0
unit_name = "approved manifest"
export_types = list(/obj/item/paper/fluff/jobs/cargo/manifest)
/datum/export/manifest_correct/applies_to(obj/O)
if(!..())
return FALSE
var/obj/item/paper/fluff/jobs/cargo/manifest/M = O
if(M.is_approved() && !M.errors)
return TRUE
return FALSE
// Correctly denied manifest.
// Refunds the package cost minus the cost of crate.
/datum/export/manifest_error_denied
cost = -500
k_elasticity = 0
unit_name = "correctly denied manifest"
export_types = list(/obj/item/paper/fluff/jobs/cargo/manifest)
/datum/export/manifest_error_denied/applies_to(obj/O)
if(!..())
return FALSE
var/obj/item/paper/fluff/jobs/cargo/manifest/M = O
if(M.is_denied() && M.errors)
return TRUE
return FALSE
/datum/export/manifest_error_denied/get_cost(obj/O)
var/obj/item/paper/fluff/jobs/cargo/manifest/M = O
return ..() + M.order_cost
// Erroneously approved manifest.
// Substracts the package cost.
/datum/export/manifest_error
unit_name = "erroneously approved manifest"
export_types = list(/obj/item/paper/fluff/jobs/cargo/manifest)
/datum/export/manifest_error/applies_to(obj/O)
if(!..())
return FALSE
var/obj/item/paper/fluff/jobs/cargo/manifest/M = O
if(M.is_approved() && M.errors)
return TRUE
return FALSE
/datum/export/manifest_error/get_cost(obj/O)
var/obj/item/paper/fluff/jobs/cargo/manifest/M = O
return -M.order_cost
// Erroneously denied manifest.
// Substracts the package cost minus the cost of crate.
/datum/export/manifest_correct_denied
cost = 500
unit_name = "erroneously denied manifest"
export_types = list(/obj/item/paper/fluff/jobs/cargo/manifest)
/datum/export/manifest_correct_denied/applies_to(obj/O)
if(!..())
return FALSE
var/obj/item/paper/fluff/jobs/cargo/manifest/M = O
if(M.is_denied() && !M.errors)
return TRUE
return FALSE
/datum/export/manifest_correct_denied/get_cost(obj/O)
var/obj/item/paper/fluff/jobs/cargo/manifest/M = O
return ..() - M.order_cost
@@ -1,8 +1,3 @@
#define EVIDENCE_TYPE_BLOOD "Blood"
#define EVIDENCE_TYPE_GSR "Gunshot Residue"
#define EVIDENCE_TYPE_SALIVA "Saliva"
#define EVIDENCE_TYPE_ADDITIONAL "Additional"
/obj/item/forensics/swab
name = "swab kit"
desc = "A sterilized cotton swab and vial used to take forensic samples."
-55
View File
@@ -1,55 +0,0 @@
#define RIOTS 1
#define WILD_ANIMAL_ATTACK 2
#define INDUSTRIAL_ACCIDENT 3
#define BIOHAZARD_OUTBREAK 4
#define WARSHIPS_ARRIVE 5
#define PIRATES 6
#define CORPORATE_ATTACK 7
#define ALIEN_RAIDERS 8
#define AI_LIBERATION 9
#define MOURNING 10
#define CULT_CELL_REVEALED 11
#define SECURITY_BREACH 12
#define ANIMAL_RIGHTS_RAID 13
#define FESTIVAL 14
#define RESEARCH_BREAKTHROUGH 15
#define BARGAINS 16
#define SONG_DEBUT 17
#define MOVIE_RELEASE 18
#define BIG_GAME_HUNTERS 19
#define ELECTION 20
#define GOSSIP 21
#define TOURISM 22
#define CELEBRITY_DEATH 23
#define RESIGNATION 24
#define DEFAULT 1
#define ADMINISTRATIVE 2
#define CLOTHING 3
#define SECURITY 4
#define SPECIAL_SECURITY 5
#define FOOD 6
#define ANIMALS 7
#define MINERALS 8
#define EMERGENCY 9
#define GAS_EVENT 10
#define MAINTENANCE 11
#define ELECTRICAL 12
#define ROBOTICS 13
#define BIOMEDICAL 14
#define GEAR_EVA 15
//---- Descriptions of destination types
//Space stations can be purpose built for a number of different things, but generally require regular shipments of essential supplies.
//Corvettes are small, fast warships generally assigned to border patrol or chasing down smugglers.
//Battleships are large, heavy cruisers designed for slugging it out with other heavies or razing planets.
//Yachts are fast civilian craft, often used for pleasure or smuggling.
//Destroyers are medium sized vessels, often used for escorting larger ships but able to go toe-to-toe with them if need be.
//Frigates are medium sized vessels, often used for escorting larger ships. They will rapidly find themselves outclassed if forced to face heavy warships head on.
-44
View File
@@ -1,44 +0,0 @@
/datum/event/disease_outbreak
announceWhen = 15
ic_name = "a viral biohazard"
/datum/event/disease_outbreak/announce()
command_announcement.Announce("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", new_sound = 'sound/AI/level_7_biohazard.ogg')
/datum/event/disease_outbreak/setup()
announceWhen = rand(15, 30)
/datum/event/disease_outbreak/start()
var/virus_type = pick(/datum/disease/dnaspread, /datum/disease/advance/flu, /datum/disease/advance/cold, /datum/disease/brainrot, /datum/disease/magnitis)
for(var/mob/living/carbon/human/H in shuffle(living_mob_list))
var/foundAlready = 0 // don't infect someone that already has the virus
var/turf/T = get_turf(H)
if(!T)
continue
if(isNotStationLevel(T.z))
continue
for(var/datum/disease/D in H.viruses)
foundAlready = 1
if(H.stat == 2 || foundAlready)
continue
if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work.
if((!H.dna) || (H.sdisabilities & BLIND)) //A blindness disease would be the worst.
continue
var/datum/disease/dnaspread/D = new
D.strain_data["name"] = H.real_name
D.strain_data["UI"] = H.dna.UI.Copy()
D.strain_data["SE"] = H.dna.SE.Copy()
D.carrier = 1
D.holder = H
D.affected_mob = H
H.viruses += D
break
else
var/datum/disease/D = new virus_type
D.carrier = 1
D.holder = H
D.affected_mob = H
H.viruses += D
break
+8
View File
@@ -128,3 +128,11 @@
/datum/event/infestation/announce()
command_announcement.Announce("[chosen_scan_type] indicate that [chosen_mob] [chosen_verb] [chosen_area]. Clear them out before this starts to affect productivity.", event_name, new_sound = 'sound/AI/vermin.ogg', zlevels = affecting_z)
#undef INFESTATION_RATS
#undef INFESTATION_LIZARDS
#undef INFESTATION_SPACE_BATS
#undef INFESTATION_SPIDERLINGS
#undef INFESTATION_HIVEBOTS
#undef INFESTATION_SLIMES
+1 -10
View File
@@ -1,12 +1,3 @@
#define NO_THOUGHT 1 //Hallucinated thoughts will not occur on this hallucination's end()
#define NO_EMOTE 2 //User will not emote to others when this hallucination ends
#define HEARING_DEPENDENT 4 //deaf characters will not experience this hallucination
//Power Defines
#define HAL_POWER_LOW 30
#define HAL_POWER_MED 50
#define HAL_POWER_HIGH 70
/datum/hallucination
var/mob/living/carbon/holder //Who is hallucinating?
var/allow_duplicates = TRUE //This is set to false for hallucinations with long durations or ones we do not want repeated for a time
@@ -62,4 +53,4 @@
//For adding accent tags when you imagine people talking to you. This will be a forced accent. If there is no accent (simplemobs), give them a random one from a list
/datum/hallucination/proc/get_hallucinated_accent(var/mob/living/talker)
return talker.accent ? talker.accent : pick(ACCENTS_ALL_IPC)
return talker.accent ? talker.accent : pick(ACCENTS_ALL_IPC)
@@ -293,3 +293,7 @@
/obj/effect/plant/proc/is_mature()
return (health >= (max_health/3) && world.time > mature_time)
#undef DEFAULT_SEED
#undef VINE_GROWTH_STAGES
@@ -1,6 +1,3 @@
#define IC_COMPONENTS_BASE 25
#define IC_COMPLEXITY_BASE 75
/obj/item/device/electronic_assembly
name = "electronic assembly"
desc = "It's a case, for building small electronics with."
-2
View File
@@ -1,5 +1,3 @@
#define MINIMUM_USEFUL_LIGHT_RANGE 1.4
/atom
var/light_power = 1 // Intensity of the light.
var/light_range = 0 // Range in tiles of the light.
+3
View File
@@ -79,3 +79,6 @@
else
to_chat(user, "<span class='warning'>You fail to pick open \the [holder].</span>")
return 0
#undef LOCK_LOCKED
#undef LOCK_BROKEN
-235
View File
@@ -1,235 +0,0 @@
/*
DMP to swapmap converter
version 1.0
by Lummox JR
*/
mob/verb/Convert(filename as file)
dmp2swapmap(filename)
/proc/d2sm_prepmap(filename)
var/txt = file2text(filename)
if(!txt) return
var/i,j
i=findText(txt,ascii2text(13)) // eliminate carriage returns
while(i)
txt=copytext(txt,1,i)+copytext(txt,i+1)
i=findText(txt,ascii2text(13),i)
i=findText(txt,"\\\n")
while(i)
for(j=i+2,j<=length(txt),++j) if(text2ascii(txt,j)>32) break
txt=copytext(txt,1,i)+copytext(txt,j)
i=findText(txt,"\\\n",i)
return txt
/proc/dmp2swapmap(filename)
//var/txt = file2text(filename)
//if(!txt) return
var/txt = d2sm_prepmap(filename)
var/mapname="[filename]"
var/i,j,k
i=findtext(mapname,".dmp")
while(i && i+4<length(mapname)) i=findtext(mapname,".dmp",i+1)
mapname=copytext(mapname,1,i)
/* i=findText(txt,ascii2text(13))
while(i)
txt=copytext(txt,1,i)+copytext(txt,i+1)
i=findText(txt,ascii2text(13),i)
i=findText(txt,"\\\n")
while(i)
for(j=i+2,j<=length(txt),++j) if(text2ascii(txt,j)>32) break
txt=copytext(txt,1,i)+copytext(txt,j)
i=findText(txt,"\\\n",i) */
var/list/codes=new
var/codelen=1
var/list/areas
var/mode=34
var/z=0
var/X=0,Y=0,Z=0
while(txt)
if(text2ascii(txt)==34)
if(mode!=34)
to_world("Corrupt map file [filename]: Unexpected code found after z-level [z]")
return
// standard line:
// "a" = (/obj, /obj, /turf, /area)
i=findtext(txt,"\"",2)
var/code=copytext(txt,2,i)
codelen=length(code)
i=findtext(txt,"(",i)
if(!i)
to_world("Corrupt map file [filename]: No type list follows \"[code]\"")
return
k=findtext(txt,"\n",++i)
j=(k || length(txt+1))
while(--j>=i && text2ascii(txt,j)!=41)
if(j<i)
to_world("Corrupt map file [filename]: Type list following \"[code]\" is incomplete")
return
var/list/L = d2sm_ParseCommaList(copytext(txt,i,j))
if(istext(L))
to_world("Corrupt map file [filename]: [L]")
return
if(L.len<2)
to_world("Corrupt map file [filename]: Type list following \"[code]\" has only 1 item")
return
txt=k?copytext(txt,k+1):null
if(L[L.len] == "[world.area]") L[L.len]=0
else
if(!areas) areas=list()
i=areas.Find(L[L.len])
if(i) L[L.len]=i
else
areas+=L[L.len]
L[L.len]=areas.len
var/codetrans=d2sm_ConvertType(L[L.len-1],"\t\t\t\t")
if(L[L.len]) codetrans+="\t\t\t\tAREA = [L[L.len]]\n"
if(L.len>2) codetrans+=d2sm_Contents(L,L.len-2,"\t\t\t\t")
codes[code]=copytext(codetrans,1,length(codetrans))
else if(text2ascii(txt)==40)
mode=40
// standard line (top-down, left-right symbol order):
// (1,1,1) = {"
// abcde
// bcdef
// "}
i=d2sm_MatchBrace(txt,1,40)
if(!i)
to_world("Corrupt map file [filename]: No matching ) for coordinates: [copytext(txt,1,findtext(txt,"\n"))]")
return
var/list/coords=d2sm_ParseCommaList(copytext(txt,2,i))
if(istext(coords) || coords.len!=3)
to_world("Corrupt map file [filename]: [istext(coords)?(coords):"[copytext(txt,1,i+1)] is not a valid (x,y,z) coordinate"]")
return
j=findtext(txt,"{",i+1)
if(!j)
to_world("Corrupt map file [filename]: No braces {} following [copytext(txt,1,i+1)]")
return
k=d2sm_MatchBrace(txt,j,123)
if(!k)
to_world("Corrupt map file [filename]: No closing brace } following [copytext(txt,1,i+1)]")
return
var/mtxt=copytext(txt,j+1,k)
if(findText(mtxt,"\"\n")!=1 || !findText(mtxt,"\n\"",length(mtxt)-1))
to_world(findText(mtxt,"\"\n"))
to_world(findText(mtxt,"\n\"",length(mtxt)-1))
to_world("Corrupt map file [filename]: No quotes in braces following [copytext(txt,1,i+1)]")
return
mtxt=copytext(mtxt,2,length(mtxt))
var/_x=0,_y=0
for(i=1,,++_y)
j=findText(mtxt,"\n",i+1)
if(!j) break
_x=max(_x,(j-i-1)/codelen)
i=j
X=max(X,_x)
Y=max(Y,_y)
z=text2num(coords[3])
Z=max(Z,z)
txt=copytext(txt,k+1)
else
i=findtext(txt,"\n")
txt=i?copytext(txt,i+1):null
to_world("Map size: [X],[Y],[Z]")
fdel("map_[mapname].txt")
var/F = file("map_[mapname].txt")
to_chat(F, ". = object(\".0\")\n.0\n\ttype = /swapmap\n\tid = \"[mapname]\"\n\tz = [Z]\n\ty = [Y]\n\tx = [X]")
if(areas)
txt=""
for(i=0,i<areas.len,++i)
txt+="[i?", ":""]object(\".[i]\")"
to_chat(F, "\tareas = list([txt])")
for(i=0,i<areas.len,++i)
to_chat(F, "\t\t.[i]")
txt=d2sm_ConvertType(areas[i+1],"\t\t\t")
to_chat(F, copytext(txt,1,length(txt)))
// 2nd pass
txt=d2sm_prepmap(filename)
while(txt)
// skip all non-data sections
if(text2ascii(txt)!=40)
i=findText(txt,"\n")
if(i) txt=copytext(txt,i+1)
else txt=null
continue
i=d2sm_MatchBrace(txt,1,40)
var/list/coords=d2sm_ParseCommaList(copytext(txt,2,i))
j=findtext(txt,"{",i+1)
k=d2sm_MatchBrace(txt,j,123)
var/mtxt=copytext(txt,j+2,k-1)
var/_x=0,_y=0
for(i=1,,++_y)
j=findText(mtxt,"\n",i+1)
if(!j) break
_x=max(_x,(j-i-1)/codelen)
i=j
// print out this z-level now
to_chat(F, "\t[coords[3]]")
i=1
for(var/y=_y,y>0,--y) // map is top-down
++i
to_chat(F, "\t\t[y]")
for(var/x in 1 to _x)
to_chat(F, "\t\t\t[x]")
j=i+codelen
to_chat(F, codes[copytext(mtxt,i,j)])
i=j
txt=copytext(txt,k+1)
/* for(z in 1 to Z)
to_chat(F, "\t[z]")
for(var/y in 1 to Y)
to_chat(F, "\t\t[y]")
for(var/x in 1 to X)
to_chat(F, "\t\t\t[x]")
to_chat(F, codes[pick(codes)] */
/proc/d2sm_ParseCommaList(txt)
var/list/L=new
var/i,ch
for(i=1,i<=length(txt),++i)
if(text2ascii(txt,i)>32) break
for(,i<=length(txt),++i)
ch=text2ascii(txt,i)
if(ch==44)
L+=copytext(txt,1,i)
for(++i,i<=length(txt),++i) if(text2ascii(txt,i)>32) break
txt=copytext(txt,i)
i=0;continue
if(ch==40 || ch==91 || ch==123)
i=d2sm_MatchBrace(txt,i,ch)
if(!i) return "No matching brace found for [ascii2text(ch)]"
if(i>1) L+=copytext(txt,1,i)
return L
/proc/d2sm_MatchBrace(txt, i, which)
if(which==40) ++which
else which+=2
var/j,ch
for(j=i+1,j<=length(txt),++j)
ch=text2ascii(txt,j)
if(ch==which) return j
if(ch==40 || ch==91 || ch==123)
j=d2sm_MatchBrace(txt,j,ch)
if(!j) return 0
/proc/d2sm_ConvertType(tt,tabs="")
var/i=findText(tt,"{")
if(!i) return "[tabs]type = [tt]\n"
.="[tabs]type = [copytext(tt,1,i)]\n"
var/list/L=d2sm_ParseCommaList(copytext(tt,i+1,d2sm_MatchBrace(tt,i,123)))
if(istext(L)) return
for(var/pair in L)
.="[.][tabs][pair]\n"
/proc/d2sm_Contents(list/conts,n,tabs="")
.="[tabs]contents = list("
var/i
for(i=0,i<n,++i)
.+="[i?", ":""]object(\".[i]\")"
.+=")\n"
tabs+="\t"
for(i=0,i<n,++i)
.+="[tabs].[i]\n"
.+=d2sm_ConvertType(conts[i+1],tabs+"\t")
+4
View File
@@ -584,3 +584,7 @@
connected.supports -= src
connected.check_supports()
connected = null
#undef DRILL_LIGHT_IDLE
#undef DRILL_LIGHT_WARNING
#undef DRILL_LIGHT_ACTIVE
+7
View File
@@ -385,3 +385,10 @@
/obj/item/farmbot_arm_assembly/attack_hand(mob/user)
return //it's a converted watertank, no you cannot pick it up and put it in your backpack
#undef FARMBOT_COLLECT
#undef FARMBOT_WATER
#undef FARMBOT_UPROOT
#undef FARMBOT_NUTRIMENT
#undef FARMBOT_PESTKILL
@@ -1,149 +0,0 @@
// MEDICAL SIDE EFFECT BASE
// ========================
/datum/medical_effect
var/name = "None"
var/strength = 0
var/start = 0
var/list/triggers
var/list/cures
var/cure_message
/datum/medical_effect/proc/manifest(mob/living/carbon/human/H)
for(var/R in cures)
if(H.reagents.has_reagent(R))
return 0
for(var/R in triggers)
if(REAGENT_VOLUME(H.reagents, R) >= triggers[R])
return 1
return 0
/datum/medical_effect/proc/on_life(mob/living/carbon/human/H, strength)
return
/datum/medical_effect/proc/cure(mob/living/carbon/human/H)
for(var/R in cures)
if(H.reagents.has_reagent(R))
if (cure_message)
to_chat(H, "<span class='notice'>[cure_message]</span>")
return 1
return 0
// MOB HELPERS
// ===========
/mob/living/carbon/human/var/list/datum/medical_effect/side_effects = list()
/mob/proc/add_side_effect(name, strength = 0)
/mob/living/carbon/human/add_side_effect(name, strength = 0)
for(var/datum/medical_effect/M in src.side_effects)
if(M.name == name)
M.strength = max(M.strength, 10)
M.start = life_tick
return
var/T = side_effects[name]
if (!T)
return
var/datum/medical_effect/M = new T
if(M.name == name)
M.strength = strength
M.start = life_tick
side_effects += M
/mob/living/carbon/human/proc/handle_medical_side_effects()
//Going to handle those things only every few ticks.
if(life_tick % 15 != 0)
return 0
var/list/L = typesof(/datum/medical_effect)-/datum/medical_effect
for(var/T in L)
var/datum/medical_effect/M = new T
if (M.manifest(src))
src.add_side_effect(M.name)
// One full cycle(in terms of strength) every 10 minutes
for (var/datum/medical_effect/M in side_effects)
if (!M) continue
var/strength_percent = sin((life_tick - M.start) / 2)
// Only do anything if the effect is currently strong enough
if(strength_percent >= 0.4)
if (M.cure(src) || M.strength > 50)
side_effects -= M
M = null
else
if(life_tick % 45 == 0)
M.on_life(src, strength_percent*M.strength)
// Effect slowly growing stronger
M.strength+=0.08
// HEADACHE
// ========
/datum/medical_effect/headache
name = "Headache"
triggers = list(/singleton/reagent/cryoxadone = 10, /singleton/reagent/bicaridine = 15, /singleton/reagent/tricordrazine = 15)
cures = list(/singleton/reagent/alkysine, /singleton/reagent/mortaphenyl, /singleton/reagent/perconol, /singleton/reagent/oxycomorphine)
cure_message = "Your head stops throbbing..."
/datum/medical_effect/headache/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("You feel a light pain in your head.",0)
if(11 to 30)
H.custom_pain("You feel a throbbing pain in your head!",1)
if(31 to INFINITY)
H.custom_pain("You feel an excrutiating pain in your head!",1)
// BAD STOMACH
// ===========
/datum/medical_effect/bad_stomach
name = "Bad Stomach"
triggers = list(/singleton/reagent/kelotane = 30, /singleton/reagent/dermaline = 15)
cures = list(/singleton/reagent/dylovene)
cure_message = "Your stomach feels a little better now..."
/datum/medical_effect/bad_stomach/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("You feel a bit light around the stomach.",0)
if(11 to 30)
H.custom_pain("Your stomach hurts.",0)
if(31 to INFINITY)
H.custom_pain("You feel sick.",1)
// CRAMPS
// ======
/datum/medical_effect/cramps
name = "Cramps"
triggers = list(/singleton/reagent/dylovene = 30, /singleton/reagent/mortaphenyl = 15)
cures = list(/singleton/reagent/inaprovaline)
cure_message = "The cramps let up..."
/datum/medical_effect/cramps/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("The muscles in your body hurt a little.",0)
if(11 to 30)
H.custom_pain("The muscles in your body cramp up painfully.",0)
if(31 to INFINITY)
H.visible_message("<b>[H]</b> flinches!")
H.custom_pain("There's pain all over your body!",1)
// ITCH
// ====
/datum/medical_effect/itch
name = "Itch"
triggers = list(/singleton/reagent/space_drugs = 10)
cures = list(/singleton/reagent/inaprovaline)
cure_message = "The itching stops..."
/datum/medical_effect/itch/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("You feel a slight itch.",0)
if(11 to 30)
H.custom_pain("You want to scratch your itch badly.",0)
if(31 to INFINITY)
H.visible_message("<b>[H]</b> shivers slightly.")
H.custom_pain("This itch makes it really hard to concentrate.",1)
@@ -1,6 +1,3 @@
#define SEC_HUDTYPE "security"
#define MED_HUDTYPE "medical"
/mob/living/carbon/human/proc/get_covered_body_parts(var/thick)
var/skipbody = 0
for(var/obj/item/clothing/C in list(wear_suit, head, wear_mask, w_uniform, gloves, shoes))
+1 -3
View File
@@ -1,5 +1,3 @@
#define DEFAULT_LAW_CHANNEL "Main Frequency"
/mob/living/silicon/proc/laws_sanity_check()
if(!src.laws)
laws = new base_law_type
@@ -106,4 +104,4 @@
/mob/living/silicon/proc/log_law(var/law_message)
log_and_message_admins(law_message)
lawchanges += "[worldtime2text()] - [usr ? "[key_name(usr)]" : "EVENT"] [law_message]"
lawchanges += "[worldtime2text()] - [usr ? "[key_name(usr)]" : "EVENT"] [law_message]"
@@ -1294,3 +1294,5 @@
/mob/living/silicon/robot/GetIdCard()
return id_card
#undef CYBORG_POWER_USAGE_MULTIPLIER
@@ -1,7 +1,3 @@
#define NO_HUD 0
#define SEC_HUD 1
#define MED_HUD 2
/mob/living/silicon
// Speaking
gender = NEUTER
@@ -283,3 +283,12 @@
if(rats.len >= RAT_KING_LEVEL)
return 1
return 0
#undef RAT_MAYOR_LEVEL
#undef RAT_BARON_LEVEL
#undef RAT_DUKE_LEVEL
#undef RAT_KING_LEVEL
#undef RAT_EMPEROR_LEVEL
#undef RAT_SAVIOR_LEVEL
#undef RAT_GOD_LEVEL
@@ -320,3 +320,10 @@
new /obj/effect/gibspawner/generic(T)
explosion(T, -1, 0, 2)
qdel(src)
#undef EGG_SCHLORRGO
#undef BABY_SCHLORRGO
#undef NORMAL_SCHLORRGO
#undef FAT_SCHLORRGO
#undef WIDE_SCHLORRGO
#undef COLOSSAL_SCHLORRGO
-4
View File
@@ -1,7 +1,3 @@
#define UPGRADE_COOLDOWN 40
#define UPGRADE_KILL_TIMER 100
//This is called from human_attackhand.dm before grabbing happens.
//IT is called when grabber tries to grab this mob
//Override this for special grab behaviour.
@@ -1,5 +1,3 @@
#define LISTENER_MODULAR_COMPUTER "modular_computers"
/obj/item/modular_computer/process()
if(!enabled) // The computer is turned off
last_power_usage = 0
@@ -95,7 +93,7 @@
if(looping_sound)
soundloop = new(src, enabled)
initial_name = name
listener = new(LISTENER_MODULAR_COMPUTER, src)
listener = new("modular_computers", src)
/obj/item/modular_computer/Destroy()
kill_program(TRUE)
@@ -247,7 +247,7 @@ var/last_message_id = 0
for (var/datum/comm_message_listener/l in comm_message_listeners)
l.Add(message)
for (var/obj/item/modular_computer/computer in get_listeners_by_type(LISTENER_MODULAR_COMPUTER, /obj/item/modular_computer))
for (var/obj/item/modular_computer/computer in get_listeners_by_type("modular_computers", /obj/item/modular_computer))
if(computer?.working && !!computer.nano_printer && computer.hard_drive?.stored_files.len)
var/datum/computer_file/program/comm/C = locate(/datum/computer_file/program/comm) in computer.hard_drive.stored_files
if(C?.intercept)
+15
View File
@@ -494,3 +494,18 @@
continue
to_chat(M, SPAN_DANGER("Suddenly the gravity pushed you up to the ceiling and dropped you back on the floor with great force!"))
M.fall_impact(1)
#undef POWER_IDLE
#undef POWER_UP
#undef POWER_DOWN
#undef GRAV_NEEDS_SCREWDRIVER
#undef GRAV_NEEDS_WELDING
#undef GRAV_NEEDS_PLASTEEL
#undef GRAV_NEEDS_WRENCH
#undef AREA_ERRNONE
#undef AREA_STATION
#undef AREA_SPACE
#undef AREA_SPECIAL
+2
View File
@@ -147,3 +147,5 @@
*******************/
/atom/proc/singuloCanEat()
return 1
#undef I_SINGULO
+5 -1
View File
@@ -1,4 +1,3 @@
#define EMITTER_DAMAGE_POWER_TRANSFER 450 //used to transfer power to containment field generators
#define EMITTER_LOOSE 0
#define EMITTER_BOLTED 1
#define EMITTER_WELDED 2
@@ -258,3 +257,8 @@
activate(null)
else
visible_message("[icon2html(src, viewers(get_turf(src)))] [src] whines, \"Access denied!\"")
#undef EMITTER_LOOSE
#undef EMITTER_BOLTED
#undef EMITTER_WELDED
@@ -1,4 +1,4 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
#define I_SINGULO "singulo"
/obj/singularity/
name = "gravitational singularity"
@@ -510,3 +510,5 @@
var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
if(destination)
forceMove(destination)
#undef I_SINGULO
-3
View File
@@ -1,6 +1,3 @@
#define SOLAR_MAX_DIST 40
#define SOLARGENRATE 1500
/obj/machinery/power/solar
name = "solar panel"
desc = "A solar electrical generator."
+3
View File
@@ -440,3 +440,6 @@
else if(closest_structure)
closest_structure.tesla_act(power, melt)
#undef TESLA_DEFAULT_POWER
#undef TESLA_MINI_POWER
@@ -1,16 +1,3 @@
#define HOLD_CASINGS 0 //do not do anything after firing. Manual action, like pump shotguns, or guns that want to define custom behaviour
#define EJECT_CASINGS 1 //drop spent casings on the ground after firing
#define CYCLE_CASINGS 2 //experimental: cycle casings, like a revolver. Also works for multibarrelled guns
#define DELETE_CASINGS 3 //deletes the casing, used in caseless ammunition guns or something
#define ROF_SMG 2 //ROF stands for "RATE OF FIRE"
#define ROF_PISTOL 3
#define ROF_INTERMEDIATE 4
#define ROF_RIFLE 5
#define ROF_HEAVY 8
#define ROF_SUPERHEAVY 12
#define ROF_UNWIELDY 16
#define ROF_SPECIAL 40
/obj/item/gun/projectile
name = "gun"
desc = "A gun that fires bullets."
+2
View File
@@ -681,3 +681,5 @@
/image/proc/flick_remove_overlay(var/atom/A)
if(A)
A.overlays.Remove(src)
#undef MUZZLE_EFFECT_PIXEL_INCREMENT
@@ -1,7 +1,5 @@
#define CELL_ALIVE(VAL) (VAL == cell_live_value)
#define KILL_CELL(CELL, NEXT_MAP) NEXT_MAP[CELL] = cell_dead_value;
#define REVIVE_CELL(CELL, NEXT_MAP) NEXT_MAP[CELL] = cell_live_value;
/datum/random_map/automata
descriptor = "generic caves"
initial_wall_cell = 55
+7
View File
@@ -223,3 +223,10 @@
return
new /datum/random_map/droppod(null, usr.x-1, usr.y-1, usr.z, supplied_drops = spawned_mobs, automated = automatic_pod)
#undef SD_FLOOR_TILE
#undef SD_WALL_TILE
#undef SD_DOOR_TILE
#undef SD_EMPTY_TILE
#undef SD_SUPPLY_TILE
@@ -1,5 +1,3 @@
#define PROCESS_REACTION_ITER 5 //when processing a reaction, iterate this many times
/datum/reagents
var/primary_reagent
var/list/reagent_volumes
+2
View File
@@ -350,3 +350,5 @@
var/obj/machinery/conveyor_switch/NC = new/obj/machinery/conveyor_switch(A, id)
transfer_fingerprints_to(NC)
qdel(src)
#undef MAX_CONVEYOR_ITEMS_MOVE
@@ -1,24 +1,4 @@
#define EFFECT_TOUCH 0
#define EFFECT_AURA 1
#define EFFECT_PULSE 2
#define MAX_EFFECT 2
#define TRIGGER_TOUCH 0
#define TRIGGER_WATER 1
#define TRIGGER_ACID 2
#define TRIGGER_VOLATILE 3
#define TRIGGER_TOXIN 4
#define TRIGGER_FORCE 5
#define TRIGGER_ENERGY 6
#define TRIGGER_HEAT 7
#define TRIGGER_COLD 8
#define TRIGGER_PHORON 9
#define TRIGGER_OXY 10
#define TRIGGER_CO2 11
#define TRIGGER_NITRO 12
#define MAX_TRIGGER 12
/obj/machinery/artifact
name = "alien artifact"
desc = "A large alien device."
-139
View File
@@ -1,139 +0,0 @@
/*
File: AST Nodes
An abstract syntax tree (AST) is a representation of source code in a computer-friendly format. It is composed of nodes,
each of which represents a certain part of the source code. For example, an <IfStatement> node represents an if statement in the
script's source code. Because it is a representation of the source code in memory, it is independent of any specific scripting language.
This allows a script in any language for which a parser exists to be run by the interpreter.
The AST is produced by an <n_Parser> object. It consists of a <GlobalBlock> with an arbitrary amount of statements. These statements are
run in order by an <n_Interpreter> object. A statement may in turn run another block (such as an if statement might if its condition is
met).
Articles:
- <http://en.wikipedia.org/wiki/Abstract_syntax_tree>
*/
var
const
/*
Constants: Operator Precedence
OOP_OR - Logical or
OOP_AND - Logical and
OOP_BIT - Bitwise operations
OOP_EQUAL - Equality checks
OOP_COMPARE - Greater than, less then, etc
OOP_ADD - Addition and subtraction
OOP_MULTIPLY - Multiplication and division
OOP_POW - Exponents
OOP_UNARY - Unary Operators
OOP_GROUP - Parentheses
*/
OOP_OR = 1 //||
OOP_AND = OOP_OR + 1 //&&
OOP_BIT = OOP_AND + 1 //&, |
OOP_EQUAL = OOP_BIT + 1 //==, !=
OOP_COMPARE = OOP_EQUAL + 1 //>, <, >=, <=
OOP_ADD = OOP_COMPARE + 1 //+, -
OOP_MULTIPLY= OOP_ADD + 1 //*, /, %
OOP_POW = OOP_MULTIPLY+ 1 //^
OOP_UNARY = OOP_POW + 1 //!
OOP_GROUP = OOP_UNARY + 1 //()
/*
Class: node
*/
/node
proc
ToString()
return "[src.type]"
/*
Class: identifier
*/
/node/identifier
var
id_name
New(id)
.=..()
src.id_name=id
ToString()
return id_name
/*
Class: expression
*/
/node/expression
/*
Class: operator
See <Binary Operators> and <Unary Operators> for subtypes.
*/
/node/expression/operator
var
node/expression/exp
tmp
name
precedence
New()
.=..()
if(!src.name) src.name="[src.type]"
ToString()
return "operator: [name]"
/*
Class: FunctionCall
*/
/node/expression/FunctionCall
//Function calls can also be expressions or statements.
var
func_name
node/identifier/object
list/parameters=new
/*
Class: literal
*/
/node/expression/value/literal
var
value
New(value)
.=..()
src.value=value
ToString()
return src.value
/*
Class: variable
*/
/node/expression/value/variable
var
node
object //Either a node/identifier or another node/expression/value/variable which points to the object
node/identifier
id
New(ident)
.=..()
id=ident
if(istext(id))id=new(id)
ToString()
return src.id.ToString()
/*
Class: reference
*/
/node/expression/value/reference
var
datum/value
New(value)
.=..()
src.value=value
ToString()
return "ref: [src.value] ([src.value.type])"
-48
View File
@@ -1,48 +0,0 @@
/*
File: Block Types
*/
/*
Class: BlockDefinition
An object representing a set of actions to perform independently from the rest of the script. Blocks are basically just
lists of statements to execute which also contain some local variables and methods. Note that since functions are local to a block,
it is possible to have a function definition inside of any type of block (such as in an if statement or another function),
and not just in the global scope as in many languages.
*/
/node/BlockDefinition
var/list
statements = new
functions = new
initial_variables = new
proc
/*
Proc: SetVar
Defines a permanent variable. The variable will not be deleted when it goes out of scope.
Notes:
Since all pre-existing temporary variables are deleted, it is not generally desirable to use this proc after the interpreter has been instantiated.
Instead, use <n_Interpreter.SetVar()>.
See Also:
- <n_Interpreter.SetVar()>
*/
SetVar(name, value)
initial_variables[name]=value
/*
Class: GlobalBlock
A block object representing the global scope.
*/
//
GlobalBlock
New()
initial_variables["null"]=null
return ..()
/*
Class: FunctionBlock
A block representing a function body.
*/
//
FunctionBlock
@@ -1,174 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/*
File: Binary Operators
*/
/*
Class: binary
Represents a binary operator in the AST. A binary operator takes two operands (ie x and y) and returns a value.
*/
/node/expression/operator/binary
var/node/expression/exp2
////////// Comparison Operators //////////
/*
Class: Equal
Returns true if x = y.
*/
//
Equal
precedence=OOP_EQUAL
/*
Class: NotEqual
Returns true if x and y aren't equal.
*/
//
NotEqual
precedence=OOP_EQUAL
/*
Class: Greater
Returns true if x > y.
*/
//
Greater
precedence=OOP_COMPARE
/*
Class: Less
Returns true if x < y.
*/
//
Less
precedence=OOP_COMPARE
/*
Class: GreaterOrEqual
Returns true if x >= y.
*/
//
GreaterOrEqual
precedence=OOP_COMPARE
/*
Class: LessOrEqual
Returns true if x <= y.
*/
//
LessOrEqual
precedence=OOP_COMPARE
////////// Logical Operators //////////
/*
Class: LogicalAnd
Returns true if x and y are true.
*/
//
LogicalAnd
precedence=OOP_AND
/*
Class: LogicalOr
Returns true if x, y, or both are true.
*/
//
LogicalOr
precedence=OOP_OR
/*
Class: LogicalXor
Returns true if either x or y but not both are true.
*/
//
LogicalXor //Not implemented in nS
precedence=OOP_OR
////////// Bitwise Operators //////////
/*
Class: BitwiseAnd
Performs a bitwise and operation.
Example:
011 & 110 = 010
*/
//
BitwiseAnd
precedence=OOP_BIT
/*
Class: BitwiseOr
Performs a bitwise or operation.
Example:
011 | 110 = 111
*/
//
BitwiseOr
precedence=OOP_BIT
/*
Class: BitwiseXor
Performs a bitwise exclusive or operation.
Example:
011 xor 110 = 101
*/
//
BitwiseXor
precedence=OOP_BIT
////////// Arithmetic Operators //////////
/*
Class: Add
Returns the sum of x and y.
*/
//
Add
precedence=OOP_ADD
/*
Class: Subtract
Returns the difference of x and y.
*/
//
Subtract
precedence=OOP_ADD
/*
Class: Multiply
Returns the product of x and y.
*/
//
Multiply
precedence=OOP_MULTIPLY
/*
Class: Divide
Returns the quotient of x and y.
*/
//
Divide
precedence=OOP_MULTIPLY
/*
Class: Power
Returns x raised to the power of y.
*/
//
Power
precedence=OOP_POW
/*
Class: Modulo
Returns the remainder of x / y.
*/
//
Modulo
precedence=OOP_MULTIPLY
@@ -1,51 +0,0 @@
/*
File: Unary Operators
*/
/*
Class: unary
Represents a unary operator in the AST. Unary operators take a single operand (referred to as x below) and return a value.
*/
/node/expression/operator/unary
precedence=OOP_UNARY
/*
Class: LogicalNot
Returns !x.
Example:
!true = false and !false = true
*/
//
LogicalNot
name="logical not"
/*
Class: BitwiseNot
Returns the value of a bitwise not operation performed on x.
Example:
~10 (decimal 2) = 01 (decimal 1).
*/
//
BitwiseNot
name="bitwise not"
/*
Class: Minus
Returns -x.
*/
//
Minus
name="minus"
/*
Class: group
A special unary operator representing a value in parentheses.
*/
//
group
precedence=OOP_GROUP
New(node/expression/exp)
src.exp=exp
return ..()
-122
View File
@@ -1,122 +0,0 @@
/*
File: Statement Types
*/
/*
Class: statement
An object representing a single instruction run by an interpreter.
*/
/node/statement
/*
Class: FunctionCall
Represents a call to a function.
*/
//
FunctionCall
var
func_name
node/identifier/object
list/parameters=new
/*
Class: FunctionDefinition
Defines a function.
*/
//
FunctionDefinition
var
func_name
list/parameters=new
node/BlockDefinition/FunctionBlock/block
/*
Class: VariableAssignment
Sets a variable in an accessible scope to the given value if one exists, otherwise initializes a new local variable to the given value.
Notes:
If a variable with the same name exists in a higher block, the value will be assigned to it. If not,
a new variable is created in the current block. To force creation of a new variable, use <VariableDeclaration>.
See Also:
- <VariableDeclaration>
*/
//
VariableAssignment
var
node
identifier
object
var_name
expression/value
/*
Class: VariableDeclaration
Intializes a local variable to a null value.
See Also:
- <VariableAssignment>
*/
//
VariableDeclaration
var
node
identifier
object
var_name
/*
Class: IfStatement
*/
//
IfStatement
var
node
BlockDefinition
block
else_block //may be null
expression/cond
/*
Class: WhileLoop
Loops while a given condition is true.
*/
//
WhileLoop
var
node
BlockDefinition/block
expression/cond
/*
Class: ForLoop
Loops while test is true, initializing a variable, increasing the variable
*/
ForLoop
var
node
BlockDefinition/block
expression/test
expression/init
expression/increment
/*
Class: BreakStatement
Ends a loop.
*/
//
BreakStatement
/*
Class: ContinueStatement
Skips to the next iteration of a loop.
*/
//
ContinueStatement
/*
Class: ReturnStatement
Ends the function and returns a value.
*/
//
ReturnStatement
var
node/expression/value
-132
View File
@@ -1,132 +0,0 @@
/*
File: Errors
*/
/*
Class: scriptError
An error scanning or parsing the source code.
*/
/scriptError
var
/*
Var: message
A message describing the problem.
*/
message
New(msg=null)
if(msg)message=msg
BadToken
message="Unexpected token: "
var/token/token
New(token/t)
token=t
if(t&&t.line) message="[t.line]: [message]"
if(istype(t))message+="[t.value]"
else message+="[t]"
InvalidID
parent_type=/scriptError/BadToken
message="Invalid identifier name: "
ReservedWord
parent_type=/scriptError/BadToken
message="Identifer using reserved word: "
BadNumber
parent_type=/scriptError/BadToken
message = "Bad number: "
BadReturn
var/token/token
message = "Unexpected return statement outside of a function."
New(token/t)
src.token=t
EndOfFile
message = "Unexpected end of file."
ExpectedToken
message="Expected: '"
New(id, token/T)
if(T && T.line) message="[T.line]: [message]"
message+="[id]'. "
if(T)message+="Found '[T.value]'."
UnterminatedComment
message="Unterminated multi-line comment statement: expected */"
DuplicateFunction
New(name, token/t)
message="Function '[name]' defined twice."
/*
Class: runtimeError
An error thrown by the interpreter in running the script.
*/
/runtimeError
var
name
/*
Var: message
A basic description as to what went wrong.
*/
message
stack/stack
proc
/*
Proc: ToString
Returns a description of the error suitable for showing to the user.
*/
ToString()
. = "[name]: [message]"
if(!stack.Top()) return
.+="\nStack:"
while(stack.Top())
var/node/statement/FunctionCall/stmt=stack.Pop()
. += "\n\t [stmt.func_name]()"
TypeMismatch
name="TypeMismatchError"
New(op, a, b)
message="Type mismatch: '[a]' [op] '[b]'"
UnexpectedReturn
name="UnexpectedReturnError"
message="Unexpected return statement."
UnknownInstruction
name="UnknownInstructionError"
message="Unknown instruction type. This may be due to incompatible compiler and interpreter versions or a lack of implementation."
UndefinedVariable
name="UndefinedVariableError"
New(variable)
message="Variable '[variable]' has not been declared."
UndefinedFunction
name="UndefinedFunctionError"
New(function)
message="Function '[function]()' has not been defined."
DuplicateVariableDeclaration
name="DuplicateVariableError"
New(variable)
message="Variable '[variable]' was already declared."
IterationLimitReached
name="MaxIterationError"
message="A loop has reached its maximum number of iterations."
RecursionLimitReached
name="MaxRecursionError"
message="The maximum amount of recursion has been reached."
DivisionByZero
name="DivideByZeroError"
message="Division by zero attempted."
MaxCPU
name="MaxComputationalUse"
message="Maximum amount of computational cycles reached (>= 1000)."
-210
View File
@@ -1,210 +0,0 @@
client/verb/tcssave()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || issilicon(mob))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
var/tcscode=winget(src, "tcscode", "text")
var/msg="[mob.name] is adding script to server [Server]: [tcscode]"
log_misc(msg)
message_admins("[mob.name] has uploaded a NTLS script to [Machine.SelectedServer] ([mob.x],[mob.y],[mob.z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[mob.x];Y=[mob.y];Z=[mob.z]'>JMP</a>)",0,1)
Server.setcode( tcscode ) // this actually saves the code from input to the server
send_output(src, null, "tcserror") // clear the errors)
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to save: Unable to locate server machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to save: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to save: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
client/verb/tcscompile()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) ))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
Server.setcode( winget(src, "tcscode", "text") ) // save code first
var/list/compileerrors = Server.compile() // then compile the code!
// Output all the compile-time errors
send_output(src, null, "tcserror")
if(compileerrors.len)
to_chat(src, "<b>Compile Errors</b>", "tcserror")
for(var/scriptError/e in compileerrors)
send_output(src, "<font color = red>\t>[e.message]</font>", "tcserror")
send_output(src, "([compileerrors.len] errors)", "tcserror")
// Output compile errors to all other people viewing the code too
for(var/mob/M in Machine.viewingcode)
if(M.client)
send_output(M, null, "tcserror")
send_output(M, "<b>Compile Errors</b>", "tcserror")
for(var/scriptError/e in compileerrors)
send_output(M, "<font color = red>\t>[e.message]</font>", "tcserror")
send_output(M, "([compileerrors.len] errors)", "tcserror")
else
send_output(src, "<font color = blue>TCS compilation successful!</font>", "tcserror")
send_output(src, "(0 errors)", "tcserror")
for(var/mob/M in Machine.viewingcode)
if(M.client)
send_output(M, "<font color = blue>TCS compilation successful!</font>", "tcserror")
send_output(M, "(0 errors)", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to compile: Unable to locate server machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to compile: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to compile: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
client/verb/tcsrun()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) ))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
Server.setcode( winget(src, "tcscode", "text") ) // save code first
var/list/compileerrors = Server.compile() // then compile the code!
// Output all the compile-time errors
send_output(src, null, "tcserror")
if(compileerrors.len)
send_output(src, "<b>Compile Errors</b>", "tcserror")
for(var/scriptError/e in compileerrors)
send_output(src, "<font color = red>\t>[e.message]</font>", "tcserror")
send_output(src, "([compileerrors.len] errors)", "tcserror")
// Output compile errors to all other people viewing the code too
for(var/mob/M in Machine.viewingcode)
if(M.client)
send_output(M, null, "tcserror")
send_output(M, "<b>Compile Errors</b>", "tcserror")
for(var/scriptError/e in compileerrors)
send_output(M, "<font color = red>\t>[e.message]</font>", "tcserror")
send_output(M, "([compileerrors.len] errors)", "tcserror")
else
// Finally, we run the code!
send_output(src, "<font color = blue>TCS compilation successful! Code executed.</font>", "tcserror")
send_output(src, "(0 errors)", "tcserror")
for(var/mob/M in Machine.viewingcode)
if(M.client)
send_output(M, "<font color = blue>TCS compilation successful!</font>", "tcserror")
send_output(M, "(0 errors)", "tcserror")
var/datum/signal/signal = new()
signal.data["message"] = ""
if(Server.freq_listening.len > 0)
signal.frequency = Server.freq_listening[1]
else
signal.frequency = PUB_FREQ
signal.data["name"] = ""
signal.data["job"] = ""
signal.data["reject"] = 0
signal.data["server"] = Server
Server.Compiler.Run(signal)
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to run: Unable to locate server machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to run: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to run: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
client/verb/exittcs()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) ))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode == mob)
Machine.storedcode = "[winget(mob, "tcscode", "text")]"
Machine.editingcode = null
else
if(mob in Machine.viewingcode)
Machine.viewingcode.Remove(mob)
client/verb/tcsrevert()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) ))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
// Replace quotation marks with quotation macros for proper winset() compatibility
var/showcode = replacetext(Server.rawcode, "\\\"", "\\\\\"")
showcode = replacetext(showcode, "\"", "\\\"")
winset(mob, "tcscode", "text=\"[showcode]\"")
send_output(src, null, "tcserror") // clear the errors
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to revert: Unable to locate server machine.</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to revert: Unable to locate machine.</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to revert: Unable to locate machine.</font>", "tcserror")
client/verb/tcsclearmem()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) ))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
Server.memory = list() // clear the memory
// Show results
to_chat(src, null, "tcserror")
to_chat(src, "<font color = blue>Server memory cleared!</font>", "tcserror")
for(var/mob/M in Machine.viewingcode)
if(M.client)
send_output(M, "<font color = blue>Server memory cleared!</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to clear memory: Unable to locate server machine.</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to clear memory: Unable to locate machine.</font>", "tcserror")
else
send_output(src, null, "tcserror")
send_output(src, "<font color = red>Failed to clear memory: Unable to locate machine.</font>", "tcserror")
@@ -1,237 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/* --- Traffic Control Scripting Language --- */
// NanoTrasen TCS Language - Made by Doohl
/n_Interpreter/TCS_Interpreter
var/datum/TCS_Compiler/Compiler
HandleError(runtimeError/e)
Compiler.Holder.add_entry(e.ToString(), "Execution Error")
/datum/TCS_Compiler
var/n_Interpreter/TCS_Interpreter/interpreter
var/obj/machinery/telecomms/server/Holder // the server that is running the code
var/ready = 1 // 1 if ready to run code
/* -- Compile a raw block of text -- */
proc/Compile(code as message)
var/n_scriptOptions/nS_Options/options = new()
var/n_Scanner/nS_Scanner/scanner = new(code, options)
var/list/tokens = scanner.Scan()
var/n_Parser/nS_Parser/parser = new(tokens, options)
var/node/BlockDefinition/GlobalBlock/program = parser.Parse()
var/list/returnerrors = list()
returnerrors += scanner.errors
returnerrors += parser.errors
if(returnerrors.len)
return returnerrors
interpreter = new(program)
interpreter.persist = 1
interpreter.Compiler= src
return returnerrors
/* -- Execute the compiled code -- */
proc/Run(var/datum/signal/subspace/vocal/signal)
if(!ready)
return
if(!interpreter)
return
interpreter.container = src
interpreter.SetVar("PI" , 3.141592653) // value of pi
interpreter.SetVar("E" , 2.718281828) // value of e
interpreter.SetVar("SQURT2" , 1.414213562) // value of the square root of 2
interpreter.SetVar("FALSE" , 0) // boolean shortcut to 0
interpreter.SetVar("TRUE" , 1) // boolean shortcut to 1
interpreter.SetVar("NORTH" , NORTH) // NORTH (1)
interpreter.SetVar("SOUTH" , SOUTH) // SOUTH (2)
interpreter.SetVar("EAST" , EAST) // EAST (4)
interpreter.SetVar("WEST" , WEST) // WEST (8)
//Language macros
interpreter.SetVar("L_BASIC", LANGUAGE_TCB)
interpreter.SetVar("L_SOL", LANGUAGE_SOL_COMMON)
interpreter.SetVar("L_ELYRAN", LANGUAGE_ELYRAN_STANDARD)
interpreter.SetVar("L_TRADE", LANGUAGE_TRADEBAND)
interpreter.SetVar("L_GUTTER", LANGUAGE_GUTTER)
interpreter.SetVar("L_MAAS", LANGUAGE_SIIK_MAAS)
interpreter.SetVar("L_YASSA", LANGUAGE_YA_SSA)
interpreter.SetVar("L_DELVAHII",LANGUAGE_DELVAHII)
interpreter.SetVar("L_DIONAEA", LANGUAGE_ROOTSONG)
interpreter.SetVar("L_UNATHI", LANGUAGE_UNATHI)
interpreter.SetVar("L_SKRELL", LANGUAGE_SKRELLIAN)
interpreter.SetVar("L_VAURCA", LANGUAGE_VAURCA)
interpreter.SetVar("L_MACHINE", LANGUAGE_EAL)
// Channel macros
interpreter.SetVar("$common", PUB_FREQ)
interpreter.SetVar("$science", SCI_FREQ)
interpreter.SetVar("$command", COMM_FREQ)
interpreter.SetVar("$medical", MED_FREQ)
interpreter.SetVar("$engineering",ENG_FREQ)
interpreter.SetVar("$security", SEC_FREQ)
interpreter.SetVar("$supply", SUP_FREQ)
// Signal data
interpreter.SetVar("$content" , signal.data["message"])
interpreter.SetVar("$freq" , signal.frequency)
interpreter.SetVar("$source" , signal.data["name"])
interpreter.SetVar("$job" , signal.data["job"])
interpreter.SetVar("$language" , signal.data["language"])
interpreter.SetVar("$sign" , signal)
interpreter.SetVar("$pass" , !(signal.data["reject"])) // if the signal isn't rejected, pass = 1; if the signal IS rejected, pass = 0
// Set up the script procs
/*
-> Send another signal to a server
@format: broadcast(content, frequency, source, job)
@param content: Message to broadcast
@param frequency: Frequency to broadcast to
@param source: The name of the source you wish to imitate. Must be stored in stored_names list.
@param job: The name of the job.
@param language: The language used for the broadcast
*/
interpreter.SetProc("broadcast", "broadcast", signal, list("message", "freq", "source", "job", "language"))
/*
-> Store a value permanently to the server machine (not the actual game hosting machine, the ingame machine)
@format: mem(address, value)
@param address: The memory address (string index) to store a value to
@param value: The value to store to the memory address
*/
interpreter.SetProc("mem", "mem", signal, list("address", "value"))
/*
-> Delay code for a given amount of deciseconds
@format: sleep(time)
@param time: time to sleep in deciseconds (1/10th second)
*/
interpreter.SetProc("sleep", /proc/delay)
/*
-> Replaces a string with another string
@format: replace(string, substring, replacestring)
@param string: the string to search for substrings (best used with $content$ constant)
@param substring: the substring to search for
@param replacestring: the string to replace the substring with
*/
interpreter.SetProc("replace", /proc/string_replacetext)
/*
-> Locates an element/substring inside of a list or string
@format: find(haystack, needle, start = 1, end = 0)
@param haystack: the container to search
@param needle: the element to search for
@param start: the position to start in
@param end: the position to end in
*/
interpreter.SetProc("find", /proc/smartfind)
/*
-> Finds the length of a string or list
@format: length(container)
@param container: the list or container to measure
*/
interpreter.SetProc("length", /proc/smartlength)
/* -- Clone functions, carried from default BYOND procs --- */
// vector namespace
interpreter.SetProc("vector", /proc/n_list)
interpreter.SetProc("at", /proc/n_listpos)
interpreter.SetProc("copy", /proc/n_listcopy)
interpreter.SetProc("push_back", /proc/n_listadd)
interpreter.SetProc("remove", /proc/n_listremove)
interpreter.SetProc("cut", /proc/n_listcut)
interpreter.SetProc("swap", /proc/n_listswap)
interpreter.SetProc("insert", /proc/n_listinsert)
interpreter.SetProc("pick", /proc/n_pick)
interpreter.SetProc("prob", /proc/prob_chance)
interpreter.SetProc("substr", /proc/docopytext)
// Donkie~
// Strings
interpreter.SetProc("lower", /proc/n_lower)
interpreter.SetProc("upper", /proc/n_upper)
interpreter.SetProc("explode", /proc/string_explode)
interpreter.SetProc("repeat", /proc/n_repeat)
interpreter.SetProc("reverse", /proc/n_reverse)
interpreter.SetProc("tonum", /proc/n_str2num)
// Numbers
interpreter.SetProc("tostring", /proc/n_num2str)
interpreter.SetProc("sqrt", /proc/n_sqrt)
interpreter.SetProc("abs", /proc/n_abs)
interpreter.SetProc("floor", /proc/n_floor)
interpreter.SetProc("ceil", /proc/n_ceil)
interpreter.SetProc("round", /proc/n_round)
interpreter.SetProc("clamp", /proc/n_clamp)
interpreter.SetProc("inrange", /proc/n_inrange)
// End of Donkie~
// Run the compiled code
interpreter.Run()
// Backwards-apply variables onto signal data
/* sanitize EVERYTHING. fucking players can't be trusted with SHIT */
signal.data["message"] = interpreter.GetVar("$content")
signal.frequency = interpreter.GetVar("$freq")
var/setname = ""
var/obj/machinery/telecomms/server/S = signal.data["server"]
if(interpreter.GetVar("$source") in S.stored_names)
setname = interpreter.GetVar("$source")
else
setname = "<i>[interpreter.GetVar("$source")]</i>"
if(signal.data["name"] != setname)
signal.data["realname"] = setname
signal.data["name"] = setname
signal.data["job"] = interpreter.GetVar("$job")
signal.data["reject"] = !(interpreter.GetVar("$pass")) // set reject to the opposite of $pass
// If the message is invalid, just don't broadcast it!
if(signal.data["message"] == "" || !signal.data["message"])
signal.data["reject"] = 1
/* -- Actual language proc code -- */
datum/signal
proc/mem(var/address, var/value)
if(istext(address))
var/obj/machinery/telecomms/server/S = data["server"]
if(!value && value != 0)
return S.memory[address]
else
S.memory[address] = value
@@ -1,261 +0,0 @@
// Script -> BYOND code procs
#define SCRIPT_MAX_REPLACEMENTS_ALLOWED 200
// --- List operations (lists known as vectors in n_script) ---
// Clone of list()
/proc/n_list()
var/list/returnlist = list()
for(var/e in args)
returnlist.Add(e)
return returnlist
// Clone of pick()
/proc/n_pick()
var/list/finalpick = list()
for(var/e in args)
if(isobject(e))
if(istype(e, /list))
var/list/sublist = e
for(var/sube in sublist)
finalpick.Add(sube)
continue
finalpick.Add(e)
return pick(finalpick)
// Clone of list[]
/proc/n_listpos(var/list/L, var/pos, var/value)
if(!istype(L, /list)) return
if(isnum(pos))
if(!value)
if(L.len >= pos)
return L[pos]
else
if(L.len >= pos)
L[pos] = value
else if(istext(pos))
if(!value)
return L[pos]
else
L[pos] = value
// Clone of list.Copy()
/proc/n_listcopy(var/list/L, var/start, var/end)
if(!istype(L, /list)) return
return L.Copy(start, end)
// Clone of list.Add()
/proc/n_listadd()
var/list/chosenlist
var/i = 1
for(var/e in args)
if(i == 1)
if(isobject(e))
if(istype(e, /list))
chosenlist = e
i = 2
else
if(chosenlist)
chosenlist.Add(e)
// Clone of list.Remove()
/proc/n_listremove()
var/list/chosenlist
var/i = 1
for(var/e in args)
if(i == 1)
if(isobject(e))
if(istype(e, /list))
chosenlist = e
i = 2
else
if(chosenlist)
chosenlist.Remove(e)
// Clone of list.Cut()
/proc/n_listcut(var/list/L, var/start, var/end)
if(!istype(L, /list)) return
return L.Cut(start, end)
// Clone of list.Swap()
/proc/n_listswap(var/list/L, var/firstindex, var/secondindex)
if(!istype(L, /list)) return
if(L.len >= secondindex && L.len >= firstindex)
return L.Swap(firstindex, secondindex)
// Clone of list.Insert()
/proc/n_listinsert(var/list/L, var/index, var/element)
if(!istype(L, /list)) return
return L.Insert(index, element)
// --- Miscellaneous functions ---
// Clone of sleep()
/proc/delay(var/time)
sleep(time)
// Clone of prob()
/proc/prob_chance(var/chance)
return prob(chance)
// Merge of list.Find() and findtext()
/proc/smartfind(var/haystack, var/needle, var/start = 1, var/end = 0)
if(haystack && needle)
if(isobject(haystack))
if(istype(haystack, /list))
if(length(haystack) >= end && start > 0)
var/list/listhaystack = haystack
return listhaystack.Find(needle, start, end)
else
if(istext(haystack))
if(length(haystack) >= end && start > 0)
return findtext(haystack, needle, start, end)
// Clone of copytext()
/proc/docopytext(var/string, var/start = 1, var/end = 0)
if(istext(string) && isnum(start) && isnum(end))
if(start > 0)
return copytext(string, start, end)
// Clone of length()
/proc/smartlength(var/container)
if(container)
if(istype(container, /list) || istext(container))
return length(container)
// BY DONKIE~
// String stuff
/proc/n_lower(var/string)
if(istext(string))
return lowertext(string)
/proc/n_upper(var/string)
if(istext(string))
return uppertext(string)
/*
//Makes a list where all indicies in a string is a seperate index in the list
// JUST A HELPER DON'T ADD TO NTSCRIPT
/proc/string_tolist(var/string)
var/list/L = new/list()
var/i
for(i=1, i<=length(string), i++)
L.Add(copytext(string, i, i))
return L
/proc/string_explode(var/string, var/separator)
if(istext(string))
if(istext(separator) && separator == "")
return string_tolist(string)
var/i
var/lasti = 1
var/list/L = new/list()
for(i=1, i<=length(string)+1, i++)
if(copytext(string, i, i+1) == separator) // We found a separator
L.Add(copytext(string, lasti, i))
lasti = i+1
L.Add(copytext(string, lasti, length(string)+1)) // Adds the last segment
return L
Just found out there was already a string explode function, did some benchmarking, and that function were a bit faster, sticking to that.
*/
/proc/string_explode(var/string, var/separator)
if(istext(string) && istext(separator))
return text2list(string, separator)
/proc/n_repeat(var/string, var/amount)
if(istext(string) && isnum(amount))
var/i
var/newstring = ""
if(length(newstring)*amount >=1000)
return
for(i=0, i<=amount, i++)
if(i>=1000)
break
newstring = newstring + string
return newstring
/proc/n_reverse(var/string)
if(istext(string))
var/newstring = ""
var/i
for(i=length(string), i>0, i--)
if(i>=1000)
break
newstring = newstring + copytext(string, i, i+1)
return newstring
// I don't know if it's neccesary to make my own proc, but I think I have to to be able to check for istext.
/proc/n_str2num(var/string)
if(istext(string))
return text2num(string)
// Number shit
/proc/n_num2str(var/num)
if(isnum(num))
return num2text(num)
// Squareroot
/proc/n_sqrt(var/num)
if(isnum(num))
return sqrt(num)
// Magnitude of num
/proc/n_abs(var/num)
if(isnum(num))
return abs(num)
// Non-recursive
// Imported from Mono string.ReplaceUnchecked
/proc/string_replacetext(var/haystack,var/a,var/b)
if(istext(haystack)&&istext(a)&&istext(b))
var/i = 1
var/lenh=length(haystack)
var/lena=length(a)
//var/lenb=length(b)
var/count = 0
var/list/dat = list()
while (i < lenh)
var/found = findtext(haystack, a, i, 0)
//log_misc("findtext([haystack], [a], [i], 0)=[found]")
if (found == 0) // Not found
break
else
if (count < SCRIPT_MAX_REPLACEMENTS_ALLOWED)
dat+=found
count+=1
else
//log_misc("Script found [a] [count] times, aborted")
break
//log_misc("Found [a] at [found]! Moving up...")
i = found + lena
if (count == 0)
return haystack
//var/nlen = lenh + ((lenb - lena) * count)
var/buf = copytext(haystack,1,dat[1]) // Prefill
var/lastReadPos = 0
for (i = 1, i <= count, i++)
var/precopy = dat[i] - lastReadPos-1
//internal static unsafe void CharCopy (String target, int targetIndex, String source, int sourceIndex, int count)
//fixed (char* dest = target, src = source)
//CharCopy (dest + targetIndex, src + sourceIndex, count);
//CharCopy (dest + curPos, source + lastReadPos, precopy);
buf+=copytext(haystack,lastReadPos,precopy)
log_misc("buf+=copytext([haystack],[lastReadPos],[precopy])")
log_misc("[buf]")
lastReadPos = dat[i] + lena
//CharCopy (dest + curPos, replace, newValue.length);
buf+=b
log_misc("[buf]")
buf+=copytext(haystack,lastReadPos, 0)
return buf
@@ -1,169 +0,0 @@
/proc/isobject(x)
return (istype(x, /datum) || istype(x, /list) || istype(x, /savefile) || istype(x, /client) || (x==world))
/n_Interpreter
proc
Eval(node/expression/exp)
if(istype(exp, /node/expression/FunctionCall))
return RunFunction(exp)
else if(istype(exp, /node/expression/operator))
return EvalOperator(exp)
else if(istype(exp, /node/expression/value/literal))
var/node/expression/value/literal/lit=exp
return lit.value
else if(istype(exp, /node/expression/value/reference))
var/node/expression/value/reference/ref=exp
return ref.value
else if(istype(exp, /node/expression/value/variable))
var/node/expression/value/variable/v=exp
if(!v.object)
return Eval(GetVariable(v.id.id_name))
else
var/datum/D
if(istype(v.object, /node/identifier))
D=GetVariable(v.object:id_name)
else
D=v.object
D=Eval(D)
if(!isobject(D))
return null
if(!D.vars.Find(v.id.id_name))
RaiseError(new/runtimeError/UndefinedVariable("[v.object.ToString()].[v.id.id_name]"))
return null
return Eval(D.vars[v.id.id_name])
else if(istype(exp, /node/expression))
RaiseError(new/runtimeError/UnknownInstruction())
else
return exp
EvalOperator(node/expression/operator/exp)
if(istype(exp, /node/expression/operator/binary))
var/node/expression/operator/binary/bin=exp
switch(bin.type)
if(/node/expression/operator/binary/Equal)
return Equal(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/NotEqual)
return NotEqual(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/Greater)
return Greater(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/Less)
return Less(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/GreaterOrEqual)
return GreaterOrEqual(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/LessOrEqual)
return LessOrEqual(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/LogicalAnd)
return LogicalAnd(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/LogicalOr)
return LogicalOr(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/LogicalXor)
return LogicalXor(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/BitwiseAnd)
return BitwiseAnd(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/BitwiseOr)
return BitwiseOr(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/BitwiseXor)
return BitwiseXor(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/Add)
return Add(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/Subtract)
return Subtract(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/Multiply)
return Multiply(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/Divide)
return Divide(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/Power)
return Power(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator/binary/Modulo)
return Modulo(Eval(bin.exp), Eval(bin.exp2))
else
RaiseError(new/runtimeError/UnknownInstruction())
else
switch(exp.type)
if(/node/expression/operator/unary/Minus)
return Minus(Eval(exp.exp))
if(/node/expression/operator/unary/LogicalNot)
return LogicalNot(Eval(exp.exp))
if(/node/expression/operator/unary/BitwiseNot)
return BitwiseNot(Eval(exp.exp))
if(/node/expression/operator/unary/group)
return Eval(exp.exp)
else
RaiseError(new/runtimeError/UnknownInstruction())
//Binary//
//Comparison operators
Equal(a, b) return a==b
NotEqual(a, b) return a!=b //LogicalNot(Equal(a, b))
Greater(a, b) return a>b
Less(a, b) return a<b
GreaterOrEqual(a, b)return a>=b
LessOrEqual(a, b) return a<=b
//Logical Operators
LogicalAnd(a, b) return a&&b
LogicalOr(a, b) return a||b
LogicalXor(a, b) return (a||b) && !(a&&b)
//Bitwise Operators
BitwiseAnd(a, b) return a&b
BitwiseOr(a, b) return a|b
BitwiseXor(a, b) return a^b
//Arithmetic Operators
Add(a, b)
if(istext(a)&&!istext(b)) b="[b]"
else if(istext(b)&&!istext(a)) a="[a]"
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("+", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("+", a, b))
return null
return a+b
Subtract(a, b)
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("-", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("-", a, b))
return null
return a-b
Divide(a, b)
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("/", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("/", a, b))
return null
if(b==0)
RaiseError(new/runtimeError/DivisionByZero())
return null
return a/b
Multiply(a, b)
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("*", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("*", a, b))
return null
return a*b
Modulo(a, b)
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("%", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("%", a, b))
return null
return a%b
Power(a, b)
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("**", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("**", a, b))
return null
return a**b
//Unary//
Minus(a) return -a
LogicalNot(a) return !a
BitwiseNot(a) return ~a
@@ -1,142 +0,0 @@
/*
File: Interpreter (Public)
Contains methods for interacting with the interpreter.
*/
/*
Class: n_Interpreter
Procedures allowing for interaction with the script that is being run by the interpreter object.
*/
/n_Interpreter
proc
/*
Proc: Load
Loads a 'compiled' script into memory.
Parameters:
program - A <GlobalBlock> object which represents the script's global scope.
*/
Load(node/BlockDefinition/GlobalBlock/program)
ASSERT(program)
src.program = program
CreateGlobalScope()
/*
Proc: Run
Runs the script.
*/
Run()
cur_recursion = 0 // reset recursion
cur_statements = 0 // reset CPU tracking
alertadmins = 0
ASSERT(src.program)
RunBlock(src.program)
/*
Proc: SetVar
Defines a global variable for the duration of the next execution of a script.
Notes:
This differs from <Block.SetVar()> in that variables set using this procedure only last for the session,
while those defined from the block object persist if it is ran multiple times.
See Also:
- <Block.SetVar()>
*/
SetVar(name, value)
if(!istext(name))
//CRASH("Invalid variable name")
return
AssignVariable(name, value)
/*
Proc: SetProc
Defines a procedure to be available to the script.
Parameters:
name - The name of the procedure as exposed to the script.
path - The typepath of a proc to be called when the function call is read by the interpreter, or, if object is specified, a string representing the procedure's name.
object - (Optional) An object which will the be target of a function call.
params - Only required if object is not null, a list of the names of parameters the proc takes.
*/
SetProc(name, path, object=null, list/params=null)
if(!istext(name))
//CRASH("Invalid function name")
return
if(!object)
globalScope.functions[name] = path
else
var/node/statement/FunctionDefinition/S = new()
S.func_name = name
S.parameters = params
S.block = new()
S.block.SetVar("src", object)
var/node/expression/FunctionCall/C = new()
C.func_name = path
C.object = new("src")
for(var/p in params)
C.parameters += new/node/expression/value/variable(p)
var/node/statement/ReturnStatement/R=new()
R.value=C
S.block.statements += R
globalScope.functions[name] = S
/*
Proc: VarExists
Checks whether a global variable with the specified name exists.
*/
VarExists(name)
return globalScope.variables.Find(name) //convert to 1/0 first?
/*
Proc: ProcExists
Checks whether a global function with the specified name exists.
*/
ProcExists(name)
return globalScope.functions.Find(name)
/*
Proc: GetVar
Returns the value of a global variable in the script. Remember to ensure that the variable exists before calling this procedure.
See Also:
- <VarExists()>
*/
GetVar(name)
if(!VarExists(name))
//CRASH("No variable named '[name]'.")
return
var/x = globalScope.variables[name]
return Eval(x)
/*
Proc: CallProc
Calls a global function defined in the script and, amazingly enough, returns its return value. Remember to ensure that the function
exists before calling this procedure.
See Also:
- <ProcExists()>
*/
CallProc(name, params[]=null)
if(!ProcExists(name))
//CRASH("No function named '[name]'.")
return
var/node/statement/FunctionDefinition/func = globalScope.functions[name]
if(istype(func))
var/node/statement/FunctionCall/stmt = new
stmt.func_name = func.func_name
stmt.parameters = params
return RunFunction(stmt)
else
return call(func)(arglist(params))
//CRASH("Unknown function type '[name]'.")
/*
Event: HandleError
Called when the interpreter throws a runtime error.
See Also:
- <runtimeError>
*/
HandleError(runtimeError/e)
@@ -1,314 +0,0 @@
/*
File: Interpreter (Internal)
*/
/*
Class: n_Interpreter
*/
/*
Macros: Status Macros
RETURNING - Indicates that the current function is returning a value.
BREAKING - Indicates that the current loop is being terminated.
CONTINUING - Indicates that the rest of the current iteration of a loop is being skipped.
*/
#define RETURNING 1
#define BREAKING 2
#define CONTINUING 4
/n_Interpreter
var
scope
curScope
globalScope
node
BlockDefinition/program
statement/FunctionDefinition/curFunction
stack
scopes = new()
functions = new()
datum/container // associated container for interpeter
/*
Var: status
A variable indicating that the rest of the current block should be skipped. This may be set to any combination of <Status Macros>.
*/
status=0
returnVal
max_statements=1000 // maximum amount of statements that can be called in one execution. this is to prevent massive crashes and exploitation
cur_statements=0 // current amount of statements called
alertadmins=0 // set to 1 if the admins shouldn't be notified of anymore issues
max_iterations=100 // max number of uninterrupted loops possible
max_recursion=50 // max recursions without returning anything (or completing the code block)
cur_recursion=0 // current amount of recursion
/*
Var: persist
If 0, global variables will be reset after Run() finishes.
*/
persist=1
paused=0
/*
Constructor: New
Calls <Load()> with the given parameters.
*/
New(node/BlockDefinition/GlobalBlock/program=null)
.=..()
if(program)Load(program)
proc
/*
Proc: RaiseError
Raises a runtime error.
*/
RaiseError(runtimeError/e)
e.stack=functions.Copy()
e.stack.Push(curFunction)
src.HandleError(e)
CreateScope(node/BlockDefinition/B)
var/scope/S = new(B, curScope)
scopes.Push(curScope)
curScope = S
return S
CreateGlobalScope()
scopes.Clear()
var/scope/S = new(program, null)
globalScope = S
return S
/*
Proc: RunBlock
Runs each statement in a block of code.
*/
RunBlock(node/BlockDefinition/Block, scope/scope = null)
var/is_global = istype(Block, /node/BlockDefinition/GlobalBlock)
if(!is_global)
if(scope)
curScope = scope
else
CreateScope(Block)
else
if(!persist)
CreateGlobalScope()
curScope = globalScope
if(cur_statements < max_statements)
for(var/node/statement/S in Block.statements)
while(paused) sleep(10)
cur_statements++
if(cur_statements >= max_statements)
RaiseError(new/runtimeError/MaxCPU())
if(container && !alertadmins)
if(istype(container, /datum/TCS_Compiler))
var/datum/TCS_Compiler/Compiler = container
var/obj/machinery/telecomms/server/Holder = Compiler.Holder
var/message = "Potential crash-inducing NTSL script detected at telecommunications server [Compiler.Holder] ([Holder.x], [Holder.y], [Holder.z])."
alertadmins = 1
message_admins(message, 1)
break
if(istype(S, /node/statement/VariableAssignment))
var/node/statement/VariableAssignment/stmt = S
var/name = stmt.var_name.id_name
if(!stmt.object)
// Below we assign the variable first to null if it doesn't already exist.
// This is necessary for assignments like +=, and when the variable is used in a function
// If the variable already exists in a different block, then AssignVariable will automatically use that one.
if(!IsVariableAccessible(name))
AssignVariable(name, null)
AssignVariable(name, Eval(stmt.value))
else
var/datum/D = Eval(GetVariable(stmt.object.id_name))
if(!D) return
D.vars[stmt.var_name.id_name] = Eval(stmt.value)
else if(istype(S, /node/statement/VariableDeclaration))
//VariableDeclaration nodes are used to forcibly declare a local variable so that one in a higher scope isn't used by default.
var/node/statement/VariableDeclaration/dec=S
if(!dec.object)
AssignVariable(dec.var_name.id_name, null, curScope)
else
var/datum/D = Eval(GetVariable(dec.object.id_name))
if(!D) return
D.vars[dec.var_name.id_name] = null
else if(istype(S, /node/statement/FunctionCall))
RunFunction(S)
else if(istype(S, /node/statement/FunctionDefinition))
//do nothing
else if(istype(S, /node/statement/WhileLoop))
RunWhile(S)
else if(istype(S, /node/statement/IfStatement))
RunIf(S)
else if(istype(S, /node/statement/ReturnStatement))
if(!curFunction)
RaiseError(new/runtimeError/UnexpectedReturn())
continue
status |= RETURNING
returnVal=Eval(S:value)
break
else if(istype(S, /node/statement/BreakStatement))
status |= BREAKING
break
else if(istype(S, /node/statement/ContinueStatement))
status |= CONTINUING
break
else
RaiseError(new/runtimeError/UnknownInstruction())
if(status)
break
curScope = scopes.Pop()
/*
Proc: RunFunction
Runs a function block or a proc with the arguments specified in the script.
*/
RunFunction(node/statement/FunctionCall/stmt)
//Note that anywhere /node/statement/FunctionCall/stmt is used so may /node/expression/FunctionCall
// If recursion gets too high (max 50 nested functions) throw an error
if(cur_recursion >= max_recursion)
RaiseError(new/runtimeError/RecursionLimitReached())
return 0
var/node/statement/FunctionDefinition/def
if(!stmt.object) //A scope's function is being called, stmt.object is null
def = GetFunction(stmt.func_name)
else if(istype(stmt.object)) //A method of an object exposed as a variable is being called, stmt.object is a /node/identifier
var/O = GetVariable(stmt.object.id_name) //Gets a reference to the object which is the target of the function call.
if(!O) return //Error already thrown in GetVariable()
def = Eval(O)
if(!def) return
cur_recursion++ // add recursion
if(istype(def))
if(curFunction) functions.Push(curFunction)
var/scope/S = CreateScope(def.block)
for(var/i=1 to def.parameters.len)
var/val
if(stmt.parameters.len>=i)
val = stmt.parameters[i]
//else
// unspecified param
AssignVariable(def.parameters[i], new/node/expression/value/literal(Eval(val)), S)
curFunction=stmt
RunBlock(def.block, S)
//Handle return value
. = returnVal
status &= ~RETURNING
returnVal=null
curFunction=functions.Pop()
cur_recursion--
else
cur_recursion--
var/list/params=new
for(var/node/expression/P in stmt.parameters)
params+=list(Eval(P))
if(isobject(def)) //def is an object which is the target of a function call
if( !hascall(def, stmt.func_name) )
RaiseError(new/runtimeError/UndefinedFunction("[stmt.object.id_name].[stmt.func_name]"))
return
return call(def, stmt.func_name)(arglist(params))
else //def is a path to a global proc
return call(def)(arglist(params))
//else
// RaiseError(new/runtimeError/UnknownInstruction())
/*
Proc: RunIf
Checks a condition and runs either the if block or else block.
*/
RunIf(node/statement/IfStatement/stmt)
if(Eval(stmt.cond))
RunBlock(stmt.block)
else if(stmt.else_block)
RunBlock(stmt.else_block)
/*
Proc: RunWhile
Runs a while loop.
*/
RunWhile(node/statement/WhileLoop/stmt)
var/i=1
while(Eval(stmt.cond) && Iterate(stmt.block, i++))
continue
status &= ~BREAKING
/*
Proc:Iterate
Runs a single iteration of a loop. Returns a value indicating whether or not to continue looping.
*/
Iterate(node/BlockDefinition/block, count)
RunBlock(block)
if(max_iterations > 0 && count >= max_iterations)
RaiseError(new/runtimeError/IterationLimitReached())
return 0
if(status & (BREAKING|RETURNING))
return 0
status &= ~CONTINUING
return 1
/*
Proc: GetFunction
Finds a function in an accessible scope with the given name. Returns a <FunctionDefinition>.
*/
GetFunction(name)
var/scope/S = curScope
while(S)
if(S.functions.Find(name))
return S.functions[name]
S = S.parent
RaiseError(new/runtimeError/UndefinedFunction(name))
/*
Proc: GetVariable
Finds a variable in an accessible scope and returns its value.
*/
GetVariable(name)
var/scope/S = curScope
while(S)
if(S.variables.Find(name))
return S.variables[name]
S = S.parent
RaiseError(new/runtimeError/UndefinedVariable(name))
GetVariableScope(name) //needed for when you reassign a variable in a higher scope
var/scope/S = curScope
while(S)
if(S.variables.Find(name))
return S
S = S.parent
IsVariableAccessible(name)
var/scope/S = curScope
while(S)
if(S.variables.Find(name))
return TRUE
S = S.parent
return FALSE
/*
Proc: AssignVariable
Assigns a value to a variable in a specific block.
Parameters:
name - The name of the variable to assign.
value - The value to assign to it.
S - The scope the variable resides in. If it is null, a scope with the variable already existing is found. If no scopes have a variable of the given name, the current scope is used.
*/
AssignVariable(name, node/expression/value, scope/S=null)
if(!S) S = GetVariableScope(name)
if(!S) S = curScope
if(!S) S = globalScope
ASSERT(istype(S))
if(istext(value) || isnum(value) || isnull(value)) value = new/node/expression/value/literal(value)
else if(!istype(value) && isobject(value)) value = new/node/expression/value/reference(value)
//TODO: check for invalid name
S.variables["[name]"] = value
@@ -1,18 +0,0 @@
/*
Class: scope
A runtime instance of a block. Used internally by the interpreter.
*/
scope
var
scope/parent = null
node/BlockDefinition/block
list
functions
variables
New(node/BlockDefinition/B, scope/parent)
src.block = B
src.parent = parent
src.variables = B.initial_variables.Copy()
src.functions = B.functions.Copy()
.=..()
-82
View File
@@ -1,82 +0,0 @@
/*
File: Options
*/
var/const //Ascii values of characters
ascii_A =65
ascii_Z =90
ascii_a =97
ascii_z =122
ascii_DOLLAR = 36 // $
ascii_ZERO=48
ascii_NINE=57
ascii_UNDERSCORE=95 // _
/*
Class: n_scriptOptions
*/
n_scriptOptions
proc
CanStartID(char) //returns true if the character can start a variable, function, or keyword name (by default letters or an underscore)
if(!isnum(char))char=text2ascii(char)
return (char in ascii_A to ascii_Z) || (char in ascii_a to ascii_z) || char==ascii_UNDERSCORE || char==ascii_DOLLAR
IsValidIDChar(char) //returns true if the character can be in the body of a variable, function, or keyword name (by default letters, numbers, and underscore)
if(!isnum(char))char=text2ascii(char)
return CanStartID(char) || IsDigit(char)
IsDigit(char)
if(!isnum(char))char=text2ascii(char)
return char in ascii_ZERO to ascii_NINE
IsValidID(id) //returns true if all the characters in the string are okay to be in an identifier name
if(!CanStartID(id)) //don't need to grab first char in id, since text2ascii does it automatically
return 0
if(length(id)==1) return 1
for(var/i=2 to length(id))
if(!IsValidIDChar(copytext(id, i, i+1)))
return 0
return 1
/*
Class: nS_Options
An implementation of <n_scriptOptions> for the n_Script language.
*/
nS_Options
var
list
symbols = list("(", ")", "\[", "]", ";", ",", "{", "}") //scanner - Characters that can be in symbols
/*
Var: keywords
An associative list used by the parser to parse keywords. Indices are strings which will trigger the keyword when parsed and the
associated values are <nS_Keyword> types of which the <n_Keyword.Parse()> proc will be called.
*/
keywords = list("if" = /n_Keyword/nS_Keyword/kwIf, "else" = /n_Keyword/nS_Keyword/kwElse, \
"while" = /n_Keyword/nS_Keyword/kwWhile, "break" = /n_Keyword/nS_Keyword/kwBreak, \
"continue" = /n_Keyword/nS_Keyword/kwContinue, \
"return" = /n_Keyword/nS_Keyword/kwReturn, "def" = /n_Keyword/nS_Keyword/kwDef)
list
assign_operators=list("=" = null, "&=" = "&",
"|=" = "|", "`=" = "`",
"+=" = "+", "-=" = "-",
"*=" = "*", "/=" = "/",
"^=" = "^",
"%=" = "%")
unary_operators =list("!" = /node/expression/operator/unary/LogicalNot, "~" = /node/expression/operator/unary/BitwiseNot,
"-" = /node/expression/operator/unary/Minus)
binary_operators=list("==" = /node/expression/operator/binary/Equal, "!=" = /node/expression/operator/binary/NotEqual,
">" = /node/expression/operator/binary/Greater, "<" = /node/expression/operator/binary/Less,
">=" = /node/expression/operator/binary/GreaterOrEqual,"<=" = /node/expression/operator/binary/LessOrEqual,
"&&" = /node/expression/operator/binary/LogicalAnd, "||" = /node/expression/operator/binary/LogicalOr,
"&" = /node/expression/operator/binary/BitwiseAnd, "|" = /node/expression/operator/binary/BitwiseOr,
"`" = /node/expression/operator/binary/BitwiseXor, "+" = /node/expression/operator/binary/Add,
"-" = /node/expression/operator/binary/Subtract, "*" = /node/expression/operator/binary/Multiply,
"/" = /node/expression/operator/binary/Divide, "^" = /node/expression/operator/binary/Power,
"%" = /node/expression/operator/binary/Modulo)
New()
.=..()
for(var/O in assign_operators+binary_operators+unary_operators)
if(!symbols.Find(O)) symbols+=O
@@ -1,312 +0,0 @@
/*
File: Expressions
Procedures for parsing expressions.
*/
/*
Macros: Expression Macros
OPERATOR - A value indicating the parser currently expects a binary operator.
VALUE - A value indicating the parser currently expects a value.
SHIFT - Tells the parser to push the current operator onto the stack.
REDUCE - Tells the parser to reduce the stack.
*/
#define OPERATOR 1
#define VALUE 2
#define SHIFT 0
#define REDUCE 1
/*
Class: nS_Parser
*/
/n_Parser/nS_Parser
var
/*
Var: expecting
A variable which keeps track of whether an operator or value is expected. It should be either <OPERATOR> or <VALUE>. See <ParseExpression()>
for more information.
*/
expecting=VALUE
proc
/*
Proc: Precedence
Compares two operators, decides which is higher in the order of operations, and returns <SHIFT> or <REDUCE>.
*/
Precedence(node/expression/operator/top, node/expression/operator/input)
if(istype(top))
top=top.precedence
if(istype(input))
input=input:precedence
if(top>=input)
return REDUCE
return SHIFT
/*
Proc: GetExpression
Takes a token expected to represent a value and returns an <expression> node.
*/
GetExpression(token/T)
if(!T) return
if(istype(T, /node/expression))
return T
switch(T.type)
if(/token/word)
return new/node/expression/value/variable(T.value)
if(/token/accessor)
var/token/accessor/A = T
var/node/expression/value/variable/E
var/stack/S = new()
while(istype(A.object, /token/accessor))
S.Push(A)
A=A.object
ASSERT(istext(A.object))
while(A)
var/node/expression/value/variable/V=new()
V.id=new(A.member)
if(E)
V.object=E
else
V.object=new/node/identifier(A.object)
E=V
A=S.Pop()
return E
if(/token/number, /token/string)
return new/node/expression/value/literal(T.value)
/*
Proc: GetOperator
Gets a path related to a token or string and returns an instance of the given type. This is used to get an instance of either a binary or unary
operator from a token.
Parameters:
O - The input value. If this is a token, O is reset to the token's value.
When O is a string and is in L, its associated value is used as the path to instantiate.
type - The desired type of the returned object.
L - The list in which to search for O.
See Also:
- <GetBinaryOperator()>
- <GetUnaryOperator()>
*/
GetOperator(O, type=/node/expression/operator, L[])
if(istype(O, type)) return O //O is already the desired type
if(istype(O, /token)) O=O:value //sets O to text
if(istext(O)) //sets O to path
if(L.Find(O)) O=L[O]
else return null
if(ispath(O))O=new O //catches path from last check
else return null //Unknown type
return O
/*
Proc: GetBinaryOperator
Uses <GetOperator()> to search for an instance of a binary operator type with which the given string is associated. For example, if
O is set to "+", an <Add> node is returned.
See Also:
- <GetOperator()>
- <GetUnaryOperator()>
*/
GetBinaryOperator(O)
return GetOperator(O, /node/expression/operator/binary, options.binary_operators)
/*
Proc: GetUnaryOperator
Uses <GetOperator()> to search for an instance of a unary operator type with which the given string is associated. For example, if
O is set to "!", a <LogicalNot> node is returned.
See Also:
- <GetOperator()>
- <GetBinaryOperator()>
*/
GetUnaryOperator(O)
return GetOperator(O, /node/expression/operator/unary, options.unary_operators)
/*
Proc: Reduce
Takes the operator on top of the opr stack and assigns its operand(s). Then this proc pushes the value of that operation to the top
of the val stack.
*/
Reduce(stack/opr, stack/val)
var/node/expression/operator/O=opr.Pop()
if(!O) return
if(!istype(O))
errors+=new/scriptError("Error reducing expression - invalid operator.")
return
//Take O and assign its operands, popping one or two values from the val stack
//depending on whether O is a binary or unary operator.
if(istype(O, /node/expression/operator/binary))
var/node/expression/operator/binary/B=O
B.exp2=val.Pop()
B.exp =val.Pop()
val.Push(B)
else
O.exp=val.Pop()
val.Push(O)
/*
Proc: EndOfExpression
Returns true if the current token represents the end of an expression.
Parameters:
end - A list of values to compare the current token to.
*/
EndOfExpression(end[])
if(!curToken)
return 1
if(istype(curToken, /token/symbol) && end.Find(curToken.value))
return 1
if(istype(curToken, /token/end) && end.Find(/token/end))
return 1
return 0
/*
Proc: ParseExpression
Uses the Shunting-yard algorithm to parse expressions.
Notes:
- When an opening parenthesis is found, then <ParseParenExpression()> is called to handle it.
- The <expecting> variable helps distinguish unary operators from binary operators (for cases like the - operator, which can be either).
Articles:
- <http://epaperpress.com/oper/>
- <http://en.wikipedia.org/wiki/Shunting-yard_algorithm>
See Also:
- <ParseFunctionExpression()>
- <ParseParenExpression()>
- <ParseParamExpression()>
*/
ParseExpression(list/end=list(/token/end), list/ErrChars=list("{", "}"))
var/stack/opr = new
var/stack/val = new
src.expecting=VALUE
while (1)
if(EndOfExpression(end))
break
if(istype(curToken, /token/symbol) && ErrChars.Find(curToken.value))
errors+=new/scriptError/BadToken(curToken)
break
if(index>tokens.len) //End of File
errors+=new/scriptError/EndOfFile()
break
var/token/ntok
if(index+1<=tokens.len)
ntok=tokens[index+1]
if(istype(curToken, /token/symbol) && curToken.value=="(") //Parse parentheses expression
if(expecting!=VALUE)
errors+=new/scriptError/ExpectedToken("operator", curToken)
NextToken()
continue
val.Push(ParseParenExpression())
else if(istype(curToken, /token/symbol)) //Operator found.
var/node/expression/operator/curOperator //Figure out whether it is unary or binary and get a new instance.
if(src.expecting==OPERATOR)
curOperator=GetBinaryOperator(curToken)
if(!curOperator)
errors+=new/scriptError/ExpectedToken("operator", curToken)
NextToken()
continue
else
curOperator=GetUnaryOperator(curToken)
if(!curOperator) //given symbol isn't a unary operator
errors+=new/scriptError/ExpectedToken("expression", curToken)
NextToken()
continue
if(opr.Top() && Precedence(opr.Top(), curOperator)==REDUCE) //Check order of operations and reduce if necessary
Reduce(opr, val)
continue
opr.Push(curOperator)
src.expecting=VALUE
else if(ntok && ntok.value=="(" && istype(ntok, /token/symbol)\
&& istype(curToken, /token/word)) //Parse function call
var/token/preToken=curToken
var/old_expect=src.expecting
var/fex=ParseFunctionExpression()
if(old_expect!=VALUE)
errors+=new/scriptError/ExpectedToken("operator", preToken)
NextToken()
continue
val.Push(fex)
else if(istype(curToken, /token/keyword)) //inline keywords
var/n_Keyword/kw=options.keywords[curToken.value]
kw=new kw(inline=1)
if(kw)
if(!kw.Parse(src))
return
else
errors+=new/scriptError/BadToken(curToken)
else if(istype(curToken, /token/end)) //semicolon found where it wasn't expected
errors+=new/scriptError/BadToken(curToken)
NextToken()
continue
else
if(expecting!=VALUE)
errors+=new/scriptError/ExpectedToken("operator", curToken)
NextToken()
continue
val.Push(GetExpression(curToken))
src.expecting=OPERATOR
NextToken()
while(opr.Top()) Reduce(opr, val) //Reduce the value stack completely
.=val.Pop() //Return what should be the last value on the stack
if(val.Top()) //
var/node/N=val.Pop()
errors+=new/scriptError("Error parsing expression. Unexpected value left on stack: [N.ToString()].")
return null
/*
Proc: ParseFunctionExpression
Parses a function call inside of an expression.
See Also:
- <ParseExpression()>
*/
ParseFunctionExpression()
var/node/expression/FunctionCall/exp=new
exp.func_name=curToken.value
NextToken() //skip function name
NextToken() //skip open parenthesis, already found
var/loops = 0
while (1)
loops++
if(loops>=1000)
CRASH("Something TERRIBLE has gone wrong in ParseFunctionExpression ;__;")
if(istype(curToken, /token/symbol) && curToken.value==")")
return exp
exp.parameters+=ParseParamExpression()
if(curToken.value==","&&istype(curToken, /token/symbol))NextToken() //skip comma
if(istype(curToken, /token/end)) //Prevents infinite loop...
errors+=new/scriptError/ExpectedToken(")")
return exp
/*
Proc: ParseParenExpression
Parses an expression that ends with a close parenthesis. This is used for parsing expressions inside of parentheses.
See Also:
- <ParseExpression()>
*/
ParseParenExpression()
if(!CheckToken("(", /token/symbol))
return
return new/node/expression/operator/unary/group(ParseExpression(list(")")))
/*
Proc: ParseParamExpression
Parses an expression that ends with either a comma or close parenthesis. This is used for parsing the parameters passed to a function call.
See Also:
- <ParseExpression()>
*/
ParseParamExpression()
return ParseExpression(list(",", ")"))
-166
View File
@@ -1,166 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/*
File: Keywords
*/
var/const/KW_FAIL = 0 //Fatal error; stop parsing entire script.
var/const/KW_PASS = 1 //OK
var/const/KW_ERR = 2 //Non-fatal error, keyword couldn't be handled properly. Ignore keyword but continue on.
var/const/KW_WARN = 3 //Warning
/*
var/const/Class: n_Keyword
var/const/Represents a special statement in the code triggered by a keyword.
*/
/n_Keyword
New(inline=0)
src.inline=inline
return ..()
/*
Var: inline
1 if the keyword is in an expression (e.g. the new keyword in many languages), 0 otherwise (such as the if and else keywords).
*/
var/inline
/*
Proc: Parse
Called when the parser finds a keyword in the code.
Parameters:
parser - The parser that created this object. You can use the parameter to manipulate the parser in order to add statements and blocks
to its AST.
*/
proc/Parse(n_Parser/parser)
/*
Class: nS_Keyword
A keyword in n_Script. By default these include return, if, else, while, and def. To enable or disable a keyword, change the
<nS_Options.keywords> list.
Behavior:
When a parser is expecting a new statement, and a keyword listed in <nS_Options.keywords> is found, it will call the keyword's
<n_Keyword.Parse()> proc.
*/
//
nS_Keyword
New(inline=0)
if(inline)
qdel(src)
kwReturn
Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock))
parser.errors+=new/scriptError/BadReturn(parser.curToken)
. = KW_WARN
var/node/statement/ReturnStatement/stmt=new
parser.NextToken() //skip 'return' token
stmt.value=parser.ParseExpression()
parser.curBlock.statements+=stmt
kwIf
Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
var/node/statement/IfStatement/stmt=new
parser.NextToken() //skip 'if' token
stmt.cond=parser.ParseParenExpression()
if(!parser.CheckToken(")", /token/symbol))
return KW_FAIL
if(!parser.CheckToken("{", /token/symbol, skip=0)) //Token needs to be preserved for parse loop, so skip=0
return KW_ERR
parser.curBlock.statements+=stmt
stmt.block=new
parser.AddBlock(stmt.block)
kwElse
Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
var/list/L=parser.curBlock.statements
var/node/statement/IfStatement/stmt
if(L&&L.len) stmt=L[L.len] //Get the last statement in the current block
if(!stmt || !istype(stmt) || stmt.else_block) //Ensure that it is an if statement
parser.errors+=new/scriptError/ExpectedToken("if statement",parser.curToken)
return KW_FAIL
parser.NextToken() //skip 'else' token
if(!parser.CheckToken("{", /token/symbol, skip=0))
return KW_ERR
stmt.else_block=new()
parser.AddBlock(stmt.else_block)
kwWhile
Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
var/node/statement/WhileLoop/stmt=new
parser.NextToken() //skip 'while' token
stmt.cond=parser.ParseParenExpression()
if(!parser.CheckToken(")", /token/symbol))
return KW_FAIL
if(!parser.CheckToken("{", /token/symbol, skip=0))
return KW_ERR
parser.curBlock.statements+=stmt
stmt.block=new
parser.AddBlock(stmt.block)
kwBreak
Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock))
parser.errors+=new/scriptError/BadToken(parser.curToken)
. = KW_WARN
var/node/statement/BreakStatement/stmt=new
parser.NextToken() //skip 'break' token
parser.curBlock.statements+=stmt
kwContinue
Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock))
parser.errors+=new/scriptError/BadToken(parser.curToken)
. = KW_WARN
var/node/statement/ContinueStatement/stmt=new
parser.NextToken() //skip 'break' token
parser.curBlock.statements+=stmt
kwDef
Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
var/node/statement/FunctionDefinition/def=new
parser.NextToken() //skip 'def' token
if(!parser.options.IsValidID(parser.curToken.value))
parser.errors+=new/scriptError/InvalidID(parser.curToken)
return KW_FAIL
def.func_name=parser.curToken.value
parser.NextToken()
if(!parser.CheckToken("(", /token/symbol))
return KW_FAIL
while (1) //for now parameters can be separated by whitespace - they don't need a comma in between
if(istype(parser.curToken, /token/symbol))
switch(parser.curToken.value)
if(",")
parser.NextToken()
if(")")
break
else
parser.errors+=new/scriptError/BadToken(parser.curToken)
return KW_ERR
else if(istype(parser.curToken, /token/word))
def.parameters+=parser.curToken.value
parser.NextToken()
else
parser.errors+=new/scriptError/InvalidID(parser.curToken)
return KW_ERR
if(!parser.CheckToken(")", /token/symbol))
return KW_FAIL
if(istype(parser.curToken, /token/end)) //Function prototype
parser.curBlock.statements+=def
else if(parser.curToken.value=="{" && istype(parser.curToken, /token/symbol))
def.block = new
parser.curBlock.statements+=def
parser.curBlock.functions[def.func_name]=def
parser.AddBlock(def.block)
else
parser.errors+=new/scriptError/BadToken(parser.curToken)
return KW_FAIL
-189
View File
@@ -1,189 +0,0 @@
/*
File: Parser
*/
/*
Class: n_Parser
An object that reads tokens and produces an AST (abstract syntax tree).
*/
/n_Parser
var
/*
Var: index
The parser's current position in the token's list.
*/
index = 1
list
/*
Var: tokens
A list of tokens in the source code generated by a scanner.
*/
tokens = new
/*
Var: errors
A list of fatal errors found by the parser. If there are any items in this list, then it is not safe to run the returned AST.
See Also:
- <scriptError>
*/
errors = new
/*
Var: warnings
A list of non-fatal problems in the script.
*/
warnings = new
token
/*
Var: curToken
The token at <index> in <tokens>.
*/
curToken
stack
blocks=new
node/BlockDefinition
GlobalBlock/global_block=new
curBlock
proc
/*
Proc: Parse
Reads the tokens and returns the AST's <GlobalBlock> node. Be sure to populate the tokens list before calling this procedure.
*/
Parse()
/*
Proc: NextToken
Sets <curToken> to the next token in the <tokens> list, or null if there are no more tokens.
*/
NextToken()
if(index>=tokens.len)
curToken=null
else
curToken=tokens[++index]
return curToken
/*
Class: nS_Parser
An implmentation of a parser for n_Script.
*/
/n_Parser/nS_Parser
var/n_scriptOptions/nS_Options/options
/*
Constructor: New
Parameters:
tokens - A list of tokens to parse.
options - An object used for configuration.
*/
New(tokens[], n_scriptOptions/options)
src.tokens=tokens
src.options=options
curBlock=global_block
return ..()
Parse()
ASSERT(tokens)
for(,src.index<=src.tokens.len, src.index++)
curToken=tokens[index]
switch(curToken.type)
if(/token/keyword)
var/n_Keyword/kw=options.keywords[curToken.value]
kw=new kw()
if(kw)
if(!kw.Parse(src))
return
if(/token/word)
var/token/ntok
if(index+1>tokens.len)
errors+=new/scriptError/BadToken(curToken)
continue
ntok=tokens[index+1]
if(!istype(ntok, /token/symbol))
errors+=new/scriptError/BadToken(ntok)
continue
if(ntok.value=="(")
ParseFunctionStatement()
else if(options.assign_operators.Find(ntok.value))
ParseAssignment()
else
errors+=new/scriptError/BadToken(ntok)
continue
if(!istype(curToken, /token/end))
errors+=new/scriptError/ExpectedToken(";", curToken)
continue
if(/token/symbol)
if(curToken.value=="}")
if(!EndBlock())
errors+=new/scriptError/BadToken(curToken)
continue
else
errors+=new/scriptError/BadToken(curToken)
continue
if(/token/end)
warnings+=new/scriptError/BadToken(curToken)
continue
else
errors+=new/scriptError/BadToken(curToken)
return
return global_block
proc
CheckToken(val, type, err=1, skip=1)
if(curToken.value!=val || !istype(curToken,type))
if(err)
errors+=new/scriptError/ExpectedToken(val, curToken)
return 0
if(skip)NextToken()
return 1
AddBlock(node/BlockDefinition/B)
blocks.Push(curBlock)
curBlock=B
EndBlock()
if(curBlock==global_block) return 0
curBlock=blocks.Pop()
return 1
ParseAssignment()
var/name=curToken.value
if(!options.IsValidID(name))
errors+=new/scriptError/InvalidID(curToken)
return
NextToken()
var/t=options.binary_operators[options.assign_operators[curToken.value]]
var/node/statement/VariableAssignment/stmt=new()
stmt.var_name=new(name)
NextToken()
if(t)
stmt.value=new t()
stmt.value:exp=new/node/expression/value/variable(stmt.var_name)
stmt.value:exp2=ParseExpression()
else
stmt.value=ParseExpression()
curBlock.statements+=stmt
ParseFunctionStatement()
if(!istype(curToken, /token/word))
errors+=new/scriptError("Bad identifier in function call.")
return
var/node/statement/FunctionCall/stmt=new
stmt.func_name=curToken.value
NextToken() //skip function name
if(!CheckToken("(", /token/symbol)) //Check for and skip open parenthesis
return
var/loops = 0
while (1)
loops++
if(loops>=6000)
CRASH("Something TERRIBLE has gone wrong in ParseFunctionStatement ;__;")
if(!curToken)
errors+=new/scriptError/EndOfFile()
return
if(istype(curToken, /token/symbol) && curToken.value==")")
curBlock.statements+=stmt
NextToken() //Skip close parenthesis
return
var/node/expression/P=ParseParamExpression()
stmt.parameters+=P
if(istype(curToken, /token/symbol) && curToken.value==",") NextToken()
-280
View File
@@ -1,280 +0,0 @@
/*
File: Scanner
*/
/*
Class: n_Scanner
An object responsible for breaking up source code into tokens for use by the parser.
*/
/n_Scanner
var/code
/*
Var: errors
A list of fatal errors found by the scanner. If there are any items in this list, then it is not safe to parse the returned tokens.
See Also:
- <scriptError>
*/
var/list/errors = new
/*
Var: warnings
A list of non-fatal problems in the source code found by the scanner.
*/
var/list/warnings = new
proc
/*
Proc: LoadCode
Loads source code.
*/
LoadCode(c)
code=c
/*
Proc: LoadCodeFromFile
Gets the code from a file and calls <LoadCode()>.
*/
LoadCodeFromFile(f)
LoadCode(file2text(f))
/*
Proc: Scan
Runs the scanner and returns the resulting list of tokens. Ensure that <LoadCode()> has been called first.
*/
Scan()
/*
Class: nS_Scanner
A scanner implementation for n_Script.
*/
/n_Scanner/nS_Scanner
/*
Variable: codepos
The scanner's position in the source code.
*/
var/codepos = 1
var/line = 1
var/linepos = 0 //column=codepos-linepos
var/n_scriptOptions/nS_Options/options
var/commenting = 0
// 1: single-line
// 2: multi-line
/*
Variable: ignore
A list of characters that are ignored by the scanner.
Default Value:
Whitespace
*/
var/list/ignore = list(" ", "\t", "\n") //Don't add tokens for whitespace
/*
Variable: end_stmt
A list of characters that end a statement. Each item may only be one character long.
Default Value:
Semicolon
*/
var/list/end_stmt = list(";")
/*
Variable: string_delim
A list of characters that can start and end strings.
Default Value:
Double and single quotes.
*/
var/list/string_delim = list("\"", "'")
/*
Variable: delim
A list of characters that denote the start of a new token. This list is automatically populated.
*/
var/list/delim = new
/*
Macro: COL
The current column number.
*/
#define COL codepos-linepos
/*
Constructor: New
Parameters:
code - The source code to tokenize.
options - An <nS_Options> object used to configure the scanner.
*/
New(code, n_scriptOptions/nS_Options/options)
.=..()
ignore+= ascii2text(13) //Carriage return
delim += ignore + options.symbols + end_stmt + string_delim
src.options=options
LoadCode(code)
Scan() //Creates a list of tokens from source code
var/list/tokens=new
for(, src.codepos<=length(code), src.codepos++)
var/char=copytext(code, codepos, codepos+1)
if(char=="\n")
line++
linepos=codepos
if(ignore.Find(char))
continue
else if(char == "/")
ReadComment()
else if(end_stmt.Find(char))
tokens+=new /token/end(char, line, COL)
else if(string_delim.Find(char))
codepos++ //skip string delimiter
tokens+=ReadString(char)
else if(options.CanStartID(char))
tokens+=ReadWord()
else if(options.IsDigit(char))
tokens+=ReadNumber()
else if(options.symbols.Find(char))
tokens+=ReadSymbol()
codepos=initial(codepos)
line=initial(line)
linepos=initial(linepos)
return tokens
proc
/*
Proc: ReadString
Reads a string in the source code into a token.
Parameters:
start - The character used to start the string.
*/
ReadString(start)
var/buf
for(, codepos <= length(code), codepos++)//codepos to length(code))
var/char=copytext(code, codepos, codepos+1)
switch(char)
if("\\") //Backslash (\) encountered in string
codepos++ //Skip next character in string, since it was escaped by a backslash
char=copytext(code, codepos, codepos+1)
switch(char)
if("\\") //Double backslash
buf+="\\"
if("n") //\n Newline
buf+="\n"
else
if(char==start) //\" Doublequote
buf+=start
else //Unknown escaped text
buf+=char
if("\n")
. = new/token/string(buf, line, COL)
errors+=new/scriptError("Unterminated string. Newline reached.", .)
line++
linepos=codepos
break
else
if(char==start) //string delimiter found, end string
break
else
buf+=char //Just a normal character in a string
if(!.) return new/token/string(buf, line, COL)
/*
Proc: ReadWord
Reads characters separated by an item in <delim> into a token.
*/
ReadWord()
var/char=copytext(code, codepos, codepos+1)
var/buf
while(!delim.Find(char) && codepos<=length(code))
buf+=char
char=copytext(code, ++codepos, codepos+1)
codepos-- //allow main Scan() proc to read the delimiter
if(options.keywords.Find(buf))
return new /token/keyword(buf, line, COL)
else
return new /token/word(buf, line, COL)
/*
Proc: ReadSymbol
Reads a symbol into a token.
*/
ReadSymbol()
var/char=copytext(code, codepos, codepos+1)
var/buf
while(options.symbols.Find(buf+char))
buf+=char
if(++codepos>length(code)) break
char=copytext(code, codepos, codepos+1)
codepos-- //allow main Scan() proc to read the next character
return new /token/symbol(buf, line, COL)
/*
Proc: ReadNumber
Reads a number into a token.
*/
ReadNumber()
var/char = copytext(code, codepos, codepos+1)
var/buf
var/dec = 0
while(options.IsDigit(char) || (char=="." && !dec))
if(char==".") dec=1
buf+=char
codepos++
char=copytext(code, codepos, codepos+1)
var/token/number/T=new(buf, line, COL)
if(isnull(text2num(buf)))
errors+=new/scriptError("Bad number: ", T)
T.value=0
codepos-- //allow main Scan() proc to read the next character
return T
/*
Proc: ReadComment
Reads a comment and outputs the type of comment
*/
ReadComment()
var/char = copytext(code, codepos, codepos+1)
var/nextchar = copytext(code, codepos+1, codepos+2)
var/charstring = char+nextchar
var/comm = 1
// 1: single-line comment
// 2: multi-line comment
var/expectedend = 0
if(charstring == "//" || charstring == "/*")
if(charstring == "/*")
comm = 2 // starts a multi-line comment
while(comm)
if(++codepos>length(code)) break
if(expectedend) // ending statement expected...
char = copytext(code, codepos, codepos+1)
if(char == "/") // ending statement found - beak the comment
comm = 0
break
if(comm == 2)
// multi-line comments are broken by ending statements
char = copytext(code, codepos, codepos+1)
if(char == "*")
expectedend = 1
continue
else
char = copytext(code, codepos, codepos+1)
if(char == "\n")
comm = 0
break
if(expectedend) expectedend = 0
if(comm == 2)
errors+=new/scriptError/UnterminatedComment()
-38
View File
@@ -1,38 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/*
Class: Token
Represents an entity and position in the source code.
*/
/token
var/value
var/line
var/column
New(v, l=0, c=0)
value=v
line=l
column=c
string
symbol
word
keyword
number
New()
.=..()
if(!isnum(value))
value=text2num(value)
ASSERT(!isnull(value))
accessor
var/object
var/member
New(object, member, l=0, c=0)
src.object=object
src.member=member
src.value="[object].[member]" //for debugging only
src.line=l
src.column=c
end
+5
View File
@@ -301,3 +301,8 @@
return prob(10)
else
return !density
#undef POWER_INACTIVE
#undef POWER_STARTING
#undef POWER_ACTIVE
@@ -190,3 +190,5 @@
//Note that this is called when the shuttle leaves the WAIT_FINISHED state, the proc name is a little misleading
/datum/shuttle/autodock/proc/arrived()
return //do nothing for now
#undef DOCK_ATTEMPT_TIMEOUT
+17 -1
View File
@@ -461,5 +461,21 @@
/obj/machinery/power/supermatter/shard/announce_warning() //Shards don't get announcements
return
#undef LIGHT_POWER_CALC
#undef NITROGEN_RETARDATION_FACTOR
#undef THERMAL_RELEASE_MODIFIER
#undef PHORON_RELEASE_MODIFIER
#undef OXYGEN_RELEASE_MODIFIER
#undef REACTION_POWER_MODIFIER
#undef POWER_FACTOR
#undef DECAY_FACTOR
#undef CRITICAL_TEMPERATURE
#undef CHARGING_FACTOR
#undef DAMAGE_RATE_LIMIT
#undef SPACED_DAMAGE_FACTOR
#undef DETONATION_RADS
#undef DETONATION_HALLUCINATION
#undef WARNING_DELAY
#undef SUPERMATTER_ACCENT_SOUND_MIN_COOLDOWN
#undef LIGHT_POWER_CALC