Merge branch 'master' into upstream-merge-31621

This commit is contained in:
LetterJay
2017-10-13 03:58:03 -04:00
committed by GitHub
38 changed files with 303 additions and 43 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ If you want to contribute the first thing you'll need to do is [set up Git](http
We have a [list of guides on the wiki](http://www.tgstation13.org/wiki/index.php/Guides#Development_and_Contribution_Guides) that will help you get started contributing to /tg/station with Git and Dream Maker. For beginners, it is recommended you work on small projects like bugfixes at first. If you need help learning to program in BYOND, check out this [repository of resources](http://www.byond.com/developer/articles/resources).
There is an open list of approachable issues for [your inspiration here](https://github.com/tgstation/-tg-station/issues?q=is%3Aopen+is%3Aissue+label%3A%22Easy+Fix%22).
There is an open list of approachable issues for [your inspiration here](https://github.com/tgstation/-tg-station/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+First+Issue%22).
You can of course, as always, ask for help at [#coderbus](irc://irc.rizon.net/coderbus) on irc.rizon.net. We're just here to have fun and help out, so please don't expect professional support.
@@ -47786,6 +47786,7 @@
pixel_y = 4
},
/obj/item/hand_tele,
/obj/item/melee/chainofcommand,
/turf/open/floor/plasteel/grimy,
/area/crew_quarters/heads/captain)
"bQC" = (
+1
View File
@@ -141,6 +141,7 @@
#define ADMIN_PUNISHMENT_BRAINDAMAGE "Brain damage"
#define ADMIN_PUNISHMENT_GIB "Gib"
#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device"
#define ADMIN_PUNISHMENT_FIREBALL "Fireball"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
+1
View File
@@ -50,6 +50,7 @@
#define SPACE_HEAT_TRANSFER_COEFFICIENT 0.2 //a hack to partly simulate radiative heat
#define OPEN_HEAT_TRANSFER_COEFFICIENT 0.4
#define WINDOW_HEAT_TRANSFER_COEFFICIENT 0.1 //a hack for now
#define HEAT_CAPACITY_VACUUM 7000 //a hack to help make vacuums "cold", sacrificing realism for gameplay
//Must be between 0 and 1. Values closer to 1 equalize temperature faster
//Should not exceed 0.4 else strange heat flow occur
#define FIRE_MINIMUM_TEMPERATURE_TO_SPREAD 150+T0C
+3 -2
View File
@@ -42,9 +42,10 @@ Last space-z level = empty
#define ZLEVEL_LAVALAND 5
#define ZLEVEL_CITYOFCOGS 6
#define ZLEVEL_EMPTY_SPACE 12
#define ZLEVEL_TRANSIT 11
//Unless you modify it in map config should be equal to ZLEVEL_SPACEMAX
#define ZLEVEL_TRANSIT 13
#define ZLEVEL_SPACEMIN 3
#define ZLEVEL_SPACEMAX 12
#define ZLEVEL_SPACEMAX 13
#define SPACERUIN_MAP_EDGE_PAD 15
+1 -5
View File
@@ -26,7 +26,7 @@
var/require_comms_key = FALSE
/datum/world_topic/proc/TryRun(list/input)
key_valid = !config || CONFIG_GET(string/comms_key) != input["key"]
key_valid = config && (CONFIG_GET(string/comms_key) == input["key"])
if(require_comms_key && !key_valid)
return "Bad Key"
input -= "key"
@@ -124,12 +124,8 @@
return NC.Run(input["sender"], input["namecheck"])
/datum/world_topic/adminwho
<<<<<<< HEAD
keyword = "namecheck"
=======
keyword = "adminwho"
require_comms_key = TRUE
>>>>>>> 9a91eeb... Add require_comms_key = TRUE to some topic that need it
/datum/world_topic/adminwho/Run(list/input)
return ircadminwho()
+1 -1
View File
@@ -450,7 +450,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(!L.client.played)
SEND_SOUND(L, sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE))
L.client.played = TRUE
addtimer(CALLBACK(L.client, /client/proc/ResetAmbiencePlayed), 600)
addtimer(CALLBACK(L.client, /client/proc/ResetAmbiencePlayed), 600)
/client/proc/ResetAmbiencePlayed()
played = FALSE
@@ -31,8 +31,5 @@
if(cell && (cell.charge / cell.maxcharge > COG_MAX_SIPHON_THRESHOLD))
cell.use(1)
adjust_clockwork_power(1) //Power is shared, so only do it once; this runs very quickly so it's about 1W/second
if(prob(1))
playsound(apc, 'sound/machines/clockcult/steam_whoosh.ogg', 10, TRUE)
new/obj/effect/temp_visual/steam(get_turf(apc), pick(GLOB.cardinals))
#undef COG_MAX_SIPHON_THRESHOLD
@@ -231,6 +231,13 @@
quickbind = TRUE
quickbind_desc = "Creates a stargazer, which generates power when near starlight."
/datum/clockwork_scripture/create_object/stargazer/check_special_requirements()
var/area/A = get_area(invoker)
if(A.outdoors || A.map_name == "Space" || !A.blob_allowed)
to_chat(invoker, "<span class='danger'>Stargazers can't be built off-station.</span>")
return
return TRUE
//Integration Cog: Creates an integration cog that can be inserted into APCs to passively siphon power.
/datum/clockwork_scripture/create_object/integration_cog
@@ -50,6 +50,10 @@
if(isspaceturf(T))
has_starlight = TRUE
break
if(has_starlight && anchored)
var/area/A = get_area(src)
if(A.outdoors || A.map_name == "Space" || !A.blob_allowed)
has_starlight = FALSE
if(old_status != has_starlight)
if(has_starlight)
visible_message("<span class='nzcrentr_small'>[src] hums and shines brilliantly!</span>")
@@ -67,6 +67,8 @@
push_over()
/obj/item/cardboard_cutout/bullet_act(obj/item/projectile/P)
if(istype(P, /obj/item/projectile/bullet/reusable))
P.on_hit(src, 0)
visible_message("<span class='danger'>[src] has been hit by [P]!</span>")
playsound(src, 'sound/weapons/slice.ogg', 50, 1)
if(prob(P.damage))
+10 -14
View File
@@ -2,11 +2,15 @@
name = "plastic explosive"
desc = "Used to put holes in specific areas without too much extra hole."
icon_state = "plastic-explosive0"
item_state = "plasticx"
item_state = "plastic-explosive"
lefthand_file = 'icons/mob/inhands/weapons/bombs_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/bombs_righthand.dmi'
flags_1 = NOBLUDGEON_1
flags_2 = NO_EMP_WIRES_2
det_time = 10
display_timer = 0
w_class = WEIGHT_CLASS_SMALL
origin_tech = "syndicate=1"
var/atom/target = null
var/mutable_appearance/plastic_overlay
var/obj/item/device/assembly_holder/nadeassembly = null
@@ -16,7 +20,7 @@
var/boom_sizes = list(0, 0, 3)
/obj/item/grenade/plastic/New()
plastic_overlay = mutable_appearance(icon, "[item_state]2")
plastic_overlay = mutable_appearance(icon, "[item_state]2", HIGH_OBJ_LAYER)
..()
/obj/item/grenade/plastic/Destroy()
@@ -112,7 +116,7 @@
message_admins("[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at [ADMIN_COORDJMP(target)] with [det_time] second fuse",0,1)
log_game("[key_name(user)] planted [name] on [target.name] at [COORD(src)] with [det_time] second fuse")
target.add_overlay(plastic_overlay, 1)
target.add_overlay(plastic_overlay, TRUE)
if(!nadeassembly)
to_chat(user, "<span class='notice'>You plant the bomb. Timer counting down from [det_time].</span>")
addtimer(CALLBACK(src, .proc/prime), det_time*10)
@@ -154,21 +158,12 @@
name = "C4"
desc = "Used to put holes in specific areas without too much extra hole. A saboteur's favorite."
gender = PLURAL
icon = 'icons/obj/grenade.dmi'
icon_state = "plastic-explosive0"
item_state = "plasticx"
lefthand_file = 'icons/mob/inhands/weapons/bombs_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/bombs_righthand.dmi'
flags_1 = NOBLUDGEON_1
w_class = WEIGHT_CLASS_SMALL
origin_tech = "syndicate=1"
var/timer = 10
var/open_panel = 0
/obj/item/grenade/plastic/c4/New()
wires = new /datum/wires/explosive/c4(src)
..()
plastic_overlay = mutable_appearance(icon, "plastic-explosive2")
/obj/item/grenade/plastic/c4/Destroy()
qdel(wires)
@@ -234,14 +229,14 @@
if(!user.temporarilyRemoveItemFromInventory(src))
return
src.target = AM
forceMove(null)
moveToNullspace()
var/message = "[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at [ADMIN_COORDJMP(target)] with [timer] second fuse"
GLOB.bombers += message
message_admins(message,0,1)
log_game("[key_name(user)] planted [name] on [target.name] at [COORD(target)] with [timer] second fuse")
target.add_overlay(plastic_overlay, 1)
target.add_overlay(plastic_overlay, TRUE)
to_chat(user, "<span class='notice'>You plant the bomb. Timer counting down from [timer].</span>")
addtimer(CALLBACK(src, .proc/explode), timer * 10)
@@ -272,5 +267,6 @@
desc = "A shaped high-explosive breaching charge. Designed to ensure user safety and wall nonsafety."
icon_state = "plasticx40"
item_state = "plasticx4"
gender = PLURAL
directional = TRUE
boom_sizes = list(0, 2, 5)
+4 -2
View File
@@ -65,10 +65,12 @@
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
/obj/item/target/bullet_act(obj/item/projectile/P)
if(istype(P, /obj/item/projectile/bullet/reusable)) // If it's a foam dart, don't bother with any of this other shit
return P.on_hit(src, 0)
var/p_x = P.p_x + pick(0,0,0,0,0,-1,1) // really ugly way of coding "sometimes offset P.p_x!"
var/p_y = P.p_y + pick(0,0,0,0,0,-1,1)
var/decaltype = DECALTYPE_SCORCH
if(istype(/obj/item/projectile/bullet, P))
if(istype(P, /obj/item/projectile/bullet))
decaltype = DECALTYPE_BULLET
var/icon/C = icon(icon,icon_state)
if(C.GetPixel(p_x, p_y) && P.original == src && overlays.len <= 35) // if the located pixel isn't blank (null)
@@ -92,4 +94,4 @@
return -1
#undef DECALTYPE_SCORCH
#undef DECALTYPE_BULLET
#undef DECALTYPE_BULLET
+2 -2
View File
@@ -121,7 +121,7 @@ GLOBAL_PROTECT(security_mode)
var/datum/world_topic/handler
for(var/I in topic_handlers)
if(input[I])
handler = I
handler = topic_handlers[I]
break
if((!handler || initial(handler.log)) && config && CONFIG_GET(flag/log_world_topic))
@@ -133,7 +133,7 @@ GLOBAL_PROTECT(security_mode)
return
handler = new handler()
return handler.Run(input)
return handler.TryRun(input)
/world/proc/AnnouncePR(announcement, list/payload)
var/static/list/PRcounts = list() //PR id -> number of times announced this round
+4 -2
View File
@@ -1166,7 +1166,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
if(!holder)
return
var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA)
var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_FIREBALL)
var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list
@@ -1186,6 +1186,8 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
target.gib(FALSE)
if(ADMIN_PUNISHMENT_BSA)
bluespace_artillery(target)
if(ADMIN_PUNISHMENT_FIREBALL)
new /obj/effect/temp_visual/target(get_turf(target))
var/msg = "[key_name_admin(usr)] punished [key_name_admin(target)] with [punishment]."
message_admins(msg)
@@ -1253,4 +1255,4 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
to_chat(usr, "<span class='danger'>ERROR: Unable to update player flags. Please check logs.</span>")
else
message_admins("[key_name_admin(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name_admin(C)]")
log_admin("[key_name(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name(C)]")
log_admin("[key_name(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name(C)]")
@@ -71,6 +71,9 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
for(var/id in cached_gases)
var/gas_data = cached_gases[id]
. += gas_data[MOLES] * gas_data[GAS_META][META_GAS_SPECIFIC_HEAT]
if(!.) //if no heat capacity, we're a vacuum - things get weird like this but this hack sorta works
. += HEAT_CAPACITY_VACUUM
/datum/gas_mixture/proc/heat_capacity_archived() //joules per kelvin
var/list/cached_gases = gases
@@ -16,7 +16,7 @@ GLOBAL_LIST_INIT(hardcoded_gases, list(/datum/gas/oxygen, /datum/gas/nitrogen, /
.[gas_path] = gas_info
/proc/gas_id2path(id)
var/meta_gas = meta_gas_list()
var/list/meta_gas = GLOB.meta_gas_info
for(var/path in meta_gas)
if(meta_gas[path][META_GAS_ID] == id)
return path
@@ -54,7 +54,7 @@
initial_temperature = TCMB
/datum/gas_mixture/immutable/space/heat_capacity()
return 7000
return HEAT_CAPACITY_VACUUM
/datum/gas_mixture/immutable/space/remove()
return copy() //we're always empty, so we can just return a copy.
@@ -217,7 +217,9 @@
if(abs(temperature_delta) > 1)
var/air_heat_capacity = air1.heat_capacity()
var/heat = ((1 - cold_protection) * 0.1 + conduction_coefficient) * temperature_delta * (1 / air_heat_capacity + 1 / heat_capacity)
var/heat = ((1 - cold_protection) * 0.1 + conduction_coefficient) * temperature_delta * (air_heat_capacity * heat_capacity / (air_heat_capacity + heat_capacity))
air1.temperature = max(air1.temperature - heat / air_heat_capacity, TCMB)
mob_occupant.bodytemperature = max(mob_occupant.bodytemperature + heat / heat_capacity, TCMB)
@@ -273,7 +273,7 @@
return ..()
/obj/machinery/portable_atmospherics/canister/obj_break(damage_flag)
if((flags_1 & BROKEN) || (flags_1 & NODECONSTRUCT_1))
if((stat & BROKEN) || (flags_1 & NODECONSTRUCT_1))
return
canister_break()
+1
View File
@@ -663,6 +663,7 @@ GLOBAL_LIST(external_rsc_urls)
return FALSE
if ("key")
return FALSE
. = ..()
/client/proc/change_view(new_size)
+12 -5
View File
@@ -18,7 +18,7 @@
S.remove_from_storage(O, src) //This will move the item to this item's contents
to_chat(user, "<span class='notice'>You empty the ore in [S] into \the [src].</span>")
else if(istype(W, /obj/item/crowbar))
playsound(loc, W.usesound, 50, 1)
playsound(src, W.usesound, 50, 1)
var/obj/item/crowbar/C = W
if(do_after(user, 50*C.toolspeed, target = src))
user.visible_message("[user] pries \the [src] apart.", "<span class='notice'>You pry apart \the [src].</span>", "<span class='italics'>You hear splitting wood.</span>")
@@ -51,8 +51,16 @@
user << browse(dat, "window=orebox")
/obj/structure/ore_box/proc/dump_box_contents()
for(var/obj/item/ore/O in contents)
O.forceMove(loc)
var/drop = drop_location()
for(var/obj/item/ore/O in src)
if(QDELETED(O))
continue
if(QDELETED(src))
break
O.forceMove(drop)
if(TICK_CHECK)
stoplag()
drop = drop_location()
/obj/structure/ore_box/Topic(href, href_list)
if(..())
@@ -64,10 +72,9 @@
src.add_fingerprint(usr)
if(href_list["removeall"])
dump_box_contents()
to_chat(usr, "<span class='notice'>You empty the box.</span>")
to_chat(usr, "<span class='notice'>You open the release hatch on the box..</span>")
updateUsrDialog()
/obj/structure/ore_box/deconstruct(disassembled = TRUE, mob/user)
var/obj/item/stack/sheet/mineral/wood/WD = new (loc, 4)
if(user)
@@ -110,6 +110,8 @@
if(obscuredTurfs[t])
if(!t.obscured)
t.obscured = image('icons/effects/cameravis.dmi', t, null, LIGHTING_LAYER+1)
t.obscured.pixel_x = -t.pixel_x
t.obscured.pixel_y = -t.pixel_y
t.obscured.plane = LIGHTING_PLANE+1
obscured += t.obscured
for(var/eye in seenby)
@@ -165,6 +167,8 @@
var/turf/t = turf
if(!t.obscured)
t.obscured = image('icons/effects/cameravis.dmi', t, null, LIGHTING_LAYER+1)
t.obscured.pixel_x = -t.pixel_x
t.obscured.pixel_y = -t.pixel_y
t.obscured.plane = LIGHTING_PLANE+1
obscured += t.obscured
+6
View File
@@ -190,11 +190,17 @@
break_light_tube(1)
return ..()
/obj/machinery/light/built
icon_state = "tube-empty"
/obj/machinery/light/built/New()
status = LIGHT_EMPTY
update(0)
..()
/obj/machinery/light/small/built
icon_state = "bulb-empty"
/obj/machinery/light/small/built/New()
status = LIGHT_EMPTY
update(0)
@@ -106,6 +106,7 @@
if("power")
on = !on
if(on)
message_admins("[key_name_admin(usr)] activated a smoke machine that contains [english_list(reagents.reagent_list)] at [ADMIN_COORDJMP(src)].")
log_admin("[key_name(usr)] activated a smoke machine that contains [english_list(reagents.reagent_list)] at [COORD(src)].")
add_logs(usr, src, "has activated [src] which contains [english_list(reagents.reagent_list)].")
if("goScreen")
+1
View File
@@ -7,6 +7,7 @@
name = "conveyor belt"
desc = "A conveyor belt."
anchored = TRUE
layer = BELOW_OPEN_DOOR_LAYER
var/operating = FALSE // 1 if running forward, -1 if backwards, 0 if off
var/operable = 1 // true if can operate (no broken segments in this belt run)
var/forwards // this is the default (forward) direction, set by the map dir
+3 -2
View File
@@ -85,14 +85,15 @@ All ShuttleMove procs go here
if(rotation)
shuttleRotate(rotation) //see shuttle_rotate.dm
loc = newT
if(length(client_mobs_in_contents))
update_parallax_contents()
return TRUE
// Called on atoms after everything has been moved
/atom/movable/proc/afterShuttleMove(list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir)
if(light)
update_light()
update_parallax_contents()
return TRUE
/////////////////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,4 @@
author: "CitadelStationBot"
delete-after: True
changes:
- bugfix: "AI eye camera static is now correctly positioned on Lavaland."
@@ -0,0 +1,4 @@
author: "WJohnston"
delete-after: True
changes:
- imageadd: "Black carpets no longer have an ugly periodic black line in them. Regular catwalks are now totally opaque so you won't accidentally click on space when trying to place wires or tiles on them."
@@ -0,0 +1,5 @@
author: "ShizCalev"
delete-after: True
changes:
- bugfix: "C4 will no longer appear underneath objects on walls."
- bugfix: "Plastic explosives will no longer be invisible after being planted."
@@ -0,0 +1,4 @@
author: "Naksu"
delete-after: True
changes:
- bugfix: "Reusable projectiles such as foam darts no longer get deleted if they're shot at a shooting range target or a cardboard cutout."
@@ -0,0 +1,4 @@
author: "ninjanomnom"
delete-after: True
changes:
- bugfix: "Mobs that didn't move during shuttle launch would not have their parallax updated. This is fixed now."
@@ -0,0 +1,5 @@
author: "Xhuis"
delete-after: True
changes:
- balance: "Stargazers can no longer be built off-station, even in new areas."
- balance: "Integration cogs no longer emit sounds and steam visuals when active."
Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 B

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

+198
View File
@@ -0,0 +1,198 @@
<?php
//Tool for web based TGUI compilation
//by Cyberboss
//RESTRICTIONS
//Restricted to Windows for now because it uses mklink cmd function
//INSTALLATION
//Setup PHP
//Place this file in it's own directory and rewrite all requests to the directory to this file
//add extension=php_fileinfo.dll to php.ini
//ensure fastcgi.impersonate is set to 0 in php.ini
//clone a tgui repository and place next to this file
//run install_dependencies.bat
//MOVE (not copy) the node_modules folder next to this file
try{
//CONFIG
$repo_dir = 'tgstation';
$path_to_tgui_from_repo = '/tgui';
$full_path_to_gulp = 'C:/Users/Cyberboss/AppData/Roaming/npm/gulp'; //this needs to be read/executable by the PHP app pool
$max_number_of_uploads = 20;
//END CONFIG
function getGitRevision()
{
global $tgdir;
$rev = trim(file_get_contents($tgdir . '/.git/HEAD'));
if (substr($rev, 0, 4) == 'ref:') {
$tmp = explode('/', $rev);
$ref = end($tmp);
$rev = trim(file_get_contents($tgdir . "/.git/refs/heads/{$ref}"));
}
return $rev;
}
function extrapolate_git_url(){
global $tgdir;
$config = file($tgdir . '/.git/config', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach($config as $line)
if(strpos($line, 'url = ') !== false)
return trim(explode('=', $line)[1]);
}
function download_file($path){
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename=' . basename($path));
header('Content-length: ' . filesize($path));
header('Pragma: no-cache');
header('Expires: 0');
readfile($path);
}
function recurse_copy($src,$dst) {
$dir = opendir($src);
@mkdir($dst);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
recurse_copy($src . '/' . $file,$dst . '/' . $file);
}
else {
copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
function rrmdir($dir) {
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (is_dir($dir."/".$object))
rrmdir($dir."/".$object);
else
unlink($dir."/".$object);
}
}
rmdir($dir);
}
}
function update_git(){
global $tgdir;
shell_exec('cd ' . $tgdir . ' && git pull');
}
$full_path_to_gulp = str_replace('/', '\\', $full_path_to_gulp);
$parent_dir = str_replace('\\', '/', realpath(dirname(__FILE__)));
$tgdir = $parent_dir . '/' . $repo_dir;
$revision = getGitRevision();
$git_base = extrapolate_git_url();
if($git_base)
$commit_url = $git_base . '/commit/' . $revision;
else
$error = 'Unable to determine github URL!';
if($_SERVER['REQUEST_METHOD'] === 'POST'){
$updated_git = isset($_POST['pull']);
if($updated_git){
update_git();
$revision = getGitRevision();
}
$good_files = array();
$finfo = new finfo(FILEINFO_MIME_TYPE);
foreach($_FILES as $F){
$name = $F['name'];
if(isset($F['error']) && !is_array($F['error']) && $F['error'] == UPLOAD_ERR_OK && $F['size'] > 0 && strpos($name, '\\') == false && strpos($name, '/') == false){
$ext = pathinfo($name, PATHINFO_EXTENSION);
$mime = $finfo->file($F['tmp_name']);
if($ext == 'ract' && $mime == 'text/plain')
$good_files[] = $F;
}
}
$the_count = count($good_files);
if($the_count > 0 && $the_count < $max_number_of_uploads){
$tgtgui_path = $tgdir . $path_to_tgui_from_repo;
$requests_dir = $parent_dir . '/requests';
if(!is_dir($requests_dir))
mkdir($requests_dir);
$target_path = str_replace('\\', '/', tempnam($requests_dir, 'tgui'));
unlink($target_path);
recurse_copy($tgtgui_path, $target_path);
$parent_node = $parent_dir . '/node_modules';
$target_node = $target_path . '/node_modules';
exec('mklink /j "' . str_replace('/', '\\', $target_node) . '" "' . str_replace('/', '\\', $parent_node) . '"');
//now copy the uploads to the thing
$target_interfaces = $target_path . '/src/interfaces/';
foreach($good_files as $F){
$target_name = $target_interfaces . $F['name'];
if(file_exists($target_name))
unlink($target_name); //remove the file
move_uploaded_file($F['tmp_name'], $target_name);
}
//compile
$command = '"' . $full_path_to_gulp . '" --cwd "' . str_replace('/', '\\', $target_path) . '" --min 2>&1';
$output = shell_exec($command);
$zip = new ZipArchive();
$zippath = $target_path . '/TGUI.zip';
if($zip->open($zippath, ZipArchive::CREATE) == TRUE){
$zip->addFile($target_path . '/assets/tgui.css', 'tgui.css');
$zip->addFile($target_path . '/assets/tgui.js', 'tgui.js');
$zip->addFromString('gulp_output.txt', $output);
$zip->close();
download_file($zippath);
}
else
$error = 'Unable to create output zipfile!';
exec('rmdir "' . str_replace('/', '\\', $target_node) . '"'); //improtant
rrmdir($target_path);
}
else if(!$updated_git)
throw new RuntimeException('No valid files uploaded!');
}
}
catch(Exception $e){
$error = $e->getMessage();
}
?>
<!DOCTYPE html>
<html>
<head>
<title>TGUI .ract Compiler</title>
</head>
<body>
<?php if(isset($error)) echo '<h5><font color="red">An error occured:</font> ' . $error . '</h5><br><br>'; ?>
<h1>Upload up to <?php echo $max_number_of_uploads; ?> .ract files<h2>
<h4>Based off revision: <?php echo isset($commit_url) ? '<a href="' . $commit_url . '">' . $revision . '</a>' : $revision; ?>
<form id='file_form' action = '' method = 'post' enctype='multipart/form-data'>
<input type='checkbox' name='pull'>Update to latest revision (don't use this unless you have to)<br>
<div id='files_field'>
<input name='f1' type='file'><br>
</div>
<button id='add_more'>Add Another File</button>
<button type='submit'>Submit</button>
</form>
</body>
<script type='text/javascript' src='https://code.jquery.com/jquery-3.2.1.min.js'></script>
<script type='text/javascript'>
$(function(){
var next_id = 2;
$("#add_more").click(function(e){
$("#files_field").append("<input name='f" + next_id + "' type='file'><br>");
++next_id;
if(next_id > <?php echo $max_number_of_uploads; ?>)
$("#add_more").remove();
});
});
</script>
</html>