you can't fix what isn't broken.
Background
So the only computer I have that will (By some miracle, given I've had it since the 90s and only tangentially upgrade it) play Gmod is presently down until I figure out which unnamed partition has the operating system and which has the personal files. The problem for me then is that, system or no, my brain keeps cycling ideas.
So one I had recently was an assembly line. That's fairly usual, get a bunch of Prop Spawners, maybe the Wire Tools, an E2 sequence, and a few hydraulics to make it put something together.
Then I extended the idea and started thinking about a bot contraption, armed with a kind of Wire multi-tool appendage like the robot arm of the assembly line, and a bunch of prop spawners. It would go around finding wounded or incomplete contraptions and repairing/finishing them, as dictated by it's E2 programming.
So then of course, one step beyond: A bot contraption that moves about the map, and is actually capable of repairing another identical bot.
I considered a bot that could repair itself, but that's pretty tricky, because it would require a robotic arm multitool that could potentially reach itself, without detaching from the main body.
So of course the obvious approach with this idea is a floating bot, because there'll be more room for maneouvering when attaching the replacement parts and wiring them together. Aside from that I'm unsure if the wire tools themselves can be turned into prop spawners, the biggest issue is the sheer magnitude of E2 code (A CPU is possible, but adds to the complexity of construction/repair and is something I'm unfamiliar with just yet) required to have these little bots run around, detect injured fellows, figure out which parts of them are broken, align themselves correctly, and then go about the repair sequence.
Current Body Iteration: Version 1.7
Current MRTA Iteration: Version 1.2
Current known code:[highlight=E2]@name Hephaestus Drone operating system
@inputs Random:wirelink
@inputs Ranger1:wirelink, Ranger2:wirelink, Ranger3:wirelink, Ranger4:wirelink, Eye:wirelink
@inputs Vec1:wirelink, Vec2:wirelink, Vec3:wirelink
@inputs L1A1:wirelink, L1A2:wirelink, L1A3:wirelink, L1S1:wirelink, L1S2a:wirelink, L1S2b:wirelink, L2A1:wirelink, L2A2:wirelink, L2A3:wirelink, L2S1a:wirelink, L2S1b:wirelink, L2S2a:wirelink, L2S2b:wirelink
@outputs BotNum, LastMes, GPS
@persist BotNum, Dir, Nsix, Status:array, Quo:array
@persist HoverAlt, VecBase, Orient, Vec1mod, Vec2mod, Vec3mod, 0T1:entity, 1T1:entity, 1T2:entity, 2T1:entity, 2T2:entity, FT1:entity
@persist Patient, Treat, NurseMode, PVec1, PVec2, PVec3
@persist Targ:entity, FolTarg, Check, TaMark
@persist Pref:array
#STARTUP
if(first()|dupe()){
timer("ghost_fill",1000)
gSetGroup("Hephaestus")
BotCount = gGetNum(1)
BotNum = BotCount + 1
gSetNum(1,BotNum)
Motion = 1
Avoidance = 1
HazAvoid = 1
VecBase = entity():isWeldedTo():massCenter()
Quo = entity():getConstraints()
Repo = 1
stoptimer("ghost_fill")}
interval(10)
DirCode = gGetStr(3)
Passcode = gGetStr(2)
#PHYSICAL
if(FT1 & 0T1 & 1T1 & 1T2 & 2T1 & 2T2){Phys = 1}
if(Phys = 1){
runOnTick(1)
Status = entity():getConstraints()
if(CntB == Status:count() & Quo:entity(CntA) != Status:entity(CntB)){
Dmgd = 1
Inj = CntA}
else{
if(Quo:entity(CntA) == Status:entity(CntB)){
CntA = Cnta + 1
CntB = 0}
else{CntB = CntB + 1}}
#DAMAGE REPORT
if(Dmgd & ~Dmgd){
PassRec = 1
Vec1 = toString(BasVec:x())+"/"+toString(BasVec:y())+"/"+toString(BasVec:z())
Vec2 = toString(OriVec:x())+"/"+toString(OriVec:y())+"/"+toString(OriVec:z())
GPSCo = toString(GPS:x)+"+"+toString(GPS:y)+"+"+toString(G PS:z)
InjMes = toString(Passcode)+" 1 "+toString(BotNum)+" "+GPSCo+" "+toString(Inj)+" "+Vec1+" "+Vec2
print(InjMes)}}
#COMMUNICATION RECEPTION
runOnChat(1)
Message = lastSaid()
if(Message:left(5) == Passcode & $Message){
ExMes = S:explode(" ",Message)
Code = ExMes:remove(1)
if(Code(1) == DirCode & Code(2) == 1|Code(1) == DirCode & Code(2) == 10){
Dir = Code(3)
if(Dir == 8 & Code(4):toNumber == BotNum){
FolTarg = Code(5)
else{Dir = Dir + -$Dir}
DirRec = 1}
elseif(Code(1) == 1){
NurseMode = 1
Patient = Code(2)
Treat = Code(4)
GPSCheck = S:explode("+",Code(3))
Vec1Base = S:explode("/",Code:string(5))
PBasVec = vec(Vec1Base:string(1):toNum(),Vec1Base:string(2): toNum(),Vec1Base:string(3):toNum())
Vec1Orient = S:explode("/",Code:string(6))
POriVec = vec(Vec1Orient:string(1):toNum(),Vec1Orient:string (2):toNum(),Vec1Orient:string(3):toNum())
#Recalculating the Passcode
if(PassRec){
NewCode = "!"+toString(Rand1)+toString(Rand2)+toString(Rand3 )+toString(Rand4)
gSetStr(2, NewCode)
PassRec = 0}
#Recalculating the Director code
if(DirRec){
NewDir = "!"+toString(Rand1)+toString(Rand2)+toString(Rand3 )
gSetStr(3,NewDir)
DirRec = 0}
#MOTION CONTROL
#POSITIONAL RESET
if(Repo){
Length1A1 = [X]
Length1A2 = [X]
Length1A3 = [X]
Length2A1 = [X]
Length2A2 = [X]
Length2A3 = [X]
HoverAlt = 100
Repo = 0}
#INTER-DRONE AVOIDANCE
if(Avoidance){
interval(500)
findClearBlackList()
findClearWhiteList()
findInSphere(entity()os(),400)
findClipToClass("gmod_wire_locator")
findSortByDistance(entity()os())
DroneDist = findResult(1):distance(findResult(2))
if(DroneDist < 100){
VecBase = -(findResult(2)os())}}
#VECTOR TRIAD
if(Motion){
interval(500)
if(!Vec1|!Vec2|!Vec3){
interval(10)
if(Vec1){
Vec1mod = entity():isWeldedTo():massCenter() - Vec1os()
if(Vec2){Vec2mod = Vec1os() - Vec2
os()}
elseif(Vec3){Vec3mod = Vec1os() - Vec2
os()}}}
Ang=(Orient-VecBase):toAngle()-Vec1os():toAngle()
Vec1:setVector("Vector") = ((VecBase + Vec1mod) + Vec1os():rotate(Ang)):setZ(HovAlt)
Vec2:setVector("Vector") = ((Vec1os() + Vec2mod) + Vec2
os():rotate(Ang)):setZ(HovAlt)
Vec3:setVector("Vector") = ((Vec1os() + Vec3mod) + Vec3
os():rotate(Ang)):setZ(HovAlt)}
#HOVER CONTROL
Alt = min(Ranger1:number("Range"),Ranger2:number("Range" ),Ranger3:number("Range"),Ranger4:number("Range"))
THoverZ = Alt - HoverAlt
if(Alt != HoverAlt){
interval(125)
HovAlt = Alt + (THoverZ/8)}}
#HYDRAULICS
#MRTA 1
#Hydraulic control for hydraulic 1A1
TLen1A1 = L1A1:number("Length") - Length1A1
if(L1A1:number("Length") != Length1A1){
interval(125)
L1A1:setNumber("Length") = L1A1:number("Length") + (TLen1A1/8)}
#Hydraulic control for hydraulic 1A2
TLen1A2 = L1A2:number("Length") - Length1A2
if(L1A2:number("Length") != Length1A2){
interval(125)
L1A2:setNumber("Length") = L1A2:number("Length") + (TLen1A2/8)}
#Hydraulic control for hydraulic 1A3
TLen1A3 = L1A3:number("Length") - Length1A3
if(L1A3:number("Length") != Length1A3){
interval(125)
L1A3:setNumber("Length") = L1A3:number("Length") + (TLen1A3/8)}
#Hydraulic control for hydraulic 1S1
TLen1S1a = L1S1a:number("Length") - Length1S1
if(L1S1a:number("Length") != Length1S1a){
interval(125)
L1S1a:setNumber("Length") = L1S1a:number("Length") + (TLen1S1a/8)}
L1S1b:setNumber("Length") = [X] - L1S1a:number("Length")
#Hydraulic control for hydraulic 1S2
TLen1S2a = L1S2a - Length1S2
if(L1S2a != Length1S2a){
interval(125)
L1S2a = L1S2a + (TLen1S2a/8)}
L1S2b:setNumber("Length") = [X] - L1S2a:number("Length")
#MRTA 2
#Hydraulic control for hydraulic 2A1
TLen2A1 = L2A1:number("Length") - Length2A1
if(L2A1:number("Length") != Length2A1){
interval(125)
L2A1:setNumber("Length") = L2A1:number("Length") + (TLen2A1/8)}
#Hydraulic control for hydraulic 2A2
TLen2A2 = L2A2:number("Length") - Length2A2
if(L2A2:number("Length") != Length2A2){
interval(125)
L2A2:setNumber("Length") = L2A2:number("Length") + (TLen2A2/8)}
#Hydraulic control for hydraulic 2A3
TLen2A3 = L2A3:number("Length") - Length2A3
if(L2A3:number("Length") != Length2A3){
interval(125)
L2A3:setNumber("Length") = L2A3:number("Length") + (TLen2A3/8)}
#Hydraulic control for hydraulic 2S1
TLen2S1a = L2S1a:number("Length") - Length2S1
if(L2S1a:number("Length") != Length2S1a){
interval(125)
L2S1a:setNumber("Length") = L2S1a:number("Length") + (TLen2S1a/8)}
L2S1b:setNumber("Length") = [X] - L2S1a:number("Length")
#Hydraulic control for hydraulic 2S2
TLen2S2a = L2S2a - Length2S2
if(L2S2a != Length2S2a){
interval(125)
L2S2a = L2S2a + (TLen2S2a/8)}
L2S2b:setNumber("Length") = [X] - L2S2a:number("Length")
#MOTOR ROTATION
#FT1 angular control
FT1Y = FT1:angles():yaw()
FT1AVY = FT1:angVel():yaw()
FT1:setNumber("Torque") = angnorm(FT1Y-FT1Yaw) + FT1AVY
#0T1 angular control
0T1Y = 0T1:angles():yaw()
0T1AVY = 0T1:angVel():yaw()
0T1:setNumber("Torque") = angnorm(0T1Y-0T1Yaw) + 0T1AVY
#1T1 angular control
1T1Y = 1T1:angles():yaw()
1T1AVY = 1T1:angVel():yaw()
1T1:setNumber("Torque") = angnorm(1T1Y-1T1Yaw) + 1T1AVY
#1T2 angular control
1T2Y = 1T2:angles():yaw()
1T2AVY = 1T2:angVel():yaw()
1T2:setNumber("Torque") = angnorm(1T2Y-1T2Yaw) + 1T2AVY
#2T1 angular control
2T1Y = 2T1:angles():yaw()
2T1AVY = 2T1:angVel():yaw()
2T1:setNumber("Torque") = angnorm(2T1Y-2T1Yaw) + 2T1AVY
#2T2 angular control
2T2Y = 2T2:angles():yaw()
2T2AVY = 2T2:angVel():yaw()
2T2:setNumber("Torque") = angnorm(2T2Y-2T2Yaw) + 2T2AVY
#DIRECTOR ACTIONS
#ACTION ALLOCATION
if(Dir == 1|Dir == 13 & NoSix == 1){Ramble = 1}
else{Ramble = 0}
if(Dir == 2|Dir == 13 & NoSix == 2){Spawn = 1}
else{Spawn = 0}
if(Dir == 3|Dir == 13 & NoSix == 3){DefSelf = 1}
else{DefSelf = 0}
if(Dir == 4|Dir == 13 & NoSix == 4){DefDir = 1}
else{DefDir = 0}
if(Dir == 5|Dir == 13 & NoSix == 5){Attack = 1}
else{Attack = 0}
if(Dir == 6|Dir == 13 & NoSix == 6){Sleep = 1}
else{Sleep = 0}
if(Dir == 7|Dir == 13 & NoSix == 7){Showroom = 1}
else{Showroom = 0}
if(Dir == 8|Dir == 13 & NoSix == 8){Follow = 1}
else{Follow = 0}
if(Dir == 9|Dir == 13 & NoSix == 9){Stop = 1}
else{Stop = 0}
if(Dir == 10|Dir == 13 & NoSix == 10){Conga = 1}
else{Conga = 0}
if(Dir == 11|Dir == 13 & NoSix == 11){Radar = 1}
else{Radar = 0}
if(Dir == 12|Dir == 13 & NoSix == 12){Guard = 1}
else{Guard = 0}
if(Dir == 13){Nsix = 1}
else{Nsix = 0}}}
if(!Nursemode){
#D06 - Sleep protocol
if(Sleep){
HoverAlt = 5
Self = entity()
interval(250)
Shake = Self:velL():length()
if($Shake < 15){
Motion = 0
if(Dir = 13){Nsix = 6}
else{Dir = 6}}
else{Repo = 1}
if{Nursemode){
Repo = 1}}
#D08 - Follow protocol
if(Follow){
if(Targ:id() != FolTarg){
findInSphere(entity()os(),1000)
interval(10)
if(FolTarg == Check:id()){
Targ = Check
elseif(TaMark == findToArray():count())
TaMark = 0
findInSphere(entity()os(),1000)}
else{
Check = findResult(TaMark)
TaMark += 1}}
TargDist = GPSVec:distance(Targos())
if(TargDist > 100){
VecBase = Targos()}}
#D09 - Stop protocol
if(Stop){
Motion = 0
HoverAlt = 0
timer("bystander",10)
Nursemode = 0
Dmgd = 0}
else{
Motion = 1
Repo = 1}
#D13 - Number Six protocol
if(first()){
Pref = array()
if(R:count(Pref) < 12){
interval(50)
NewPoi = (R:count(Pref) + 1)
Pref:setNumber(NewPoi,NewPoi)}}
if(Nsix){
#I am not a number, I am a FREE MAN!
interval(60000)
Index = round(random(1,R:count(Pref)))
NoSix = Pref:number(Index)
NewPoi = Index + 1
NewEnt = round(random(1,[X]))
Pref:setNumber(NewEnt,NewPoi)}[/highlight][highlight=E2]@name Hephaestus memory chip
@inputs OS:wirelink
@outputs DroneID, MesRec:array, GPS
@persist BotNum, MesRec:array, GPS:vector, GPSCo:string, Torso:entity, Age, TOD
#STARTUP
if(first()){
TorCol = vec(255,246,225)
Bod = entity():getConstraints()
Body = Bod:entity(Mark)
gSetGroup("Hephaestus")
MesRec = array()
if(!Body){
interval(10)
if(Body:getColor():toString() == TorCol){Torso = Body}
else{Mark += 1}}
#DRONE ID
if(Body)
interval(1000)
Age += 1}
DroneID = "Heph-"+toString(OS:number("BotNum"))+"-"+toString(Age)+"-"+toString(TOD)
#DRONE DEATH
#Dead census
if(!Body & !$Body){
gGetNum(4)
gSetNum(4) += 1
#Time Of Death
TOD = curtime()}
GPSCo = toString(OS:vector("GPS"):x())+"+"+toString(OS:vec tor("GPS"):y())+"+"+toString(OS:vector("GPS"):z())
#Death alert
timer("alert",random(10,40))
DeathLen = 14 + toString(BotNum):length()
DeathMes = "Deceased-"+DroneID:left(DeathLen-9)
if(!lastSaid():left(DeathLen) == DeathMes){
print("Deceased-"+DroneID+GPSCo)
stoptimer("alert")}
else{stoptimer("alert")}
#Last 10 messages
if($LastMes){
if(MesRec:count() = 10){
MesRec:shiftString()
MesRecushString(LastMes)}
else{MesRecushString(LastMes)}}[/highlight]Global variable group: Hephaestus
Global variables: BotCount, Passcode, DirCodePhew, okay, that's my massive chunk of info out of my noggin. Feel free to comment, critique, crush mercilessly, or clear out quietly looking at me funny.
Last edited by Lyinginbedmon; 05-28-2009 at 02:59 PM. Reason: MASSIVE motion for the OS to Wirelinks
you can't fix what isn't broken.
Or just make portions of the bots out of destructable props.
Or even just Gcombat.
Last edited by Lyinginbedmon; 03-29-2009 at 09:55 AM.
Cool idea, which really is only possible through S-tool turrets. Not many servers have that addon though, so if you wanted to use this online, well... you can't.
Certainly an ambitious project. Though it's been a while since the last time I quite enjoy a spot of automating in Gmod myself. Never really tried for von Neumann machines, though, and lack of tools has been a factor in that. I don't think the existing stool turrets by themselves are really going to cut it here. Maybe if they had a string input where you can put in an stool name for them to emulate.
I wish you luck, in any case.
I can wire anything directly into anything! I'm the Professor!
-Professor Hubert Farnsworth
I have suggested implementing a S-tool entity or tool into Wiremod before, but I'm reasonably certain that even in single player this'd be awesome just to watch, especially with the previously suggested remover tool bot or even just some angry NPCs.
Okay, obviously most of my thought processes about this project in the past few hours have been following the lines of how the tool mount (MRTA) is constructed.
Oh, I also named them
As the diagram shows, the tool mount is rotatable upon a wheel, largely to be used for selecting the required tool for each task. The wheel is mounted on a swashplate, so tool can be further manouvered to point into tighter angles than the arm alone would allow. The tools themselves are arranged around the outer edges (The mount is shown as a square plate, but should probably be circular) with a grabber placed centrally for picking up replacement parts and placing them. Unlike what the diagram shows, the swashplate is mounted flush to the end of the extendable arm, not parallel with it.
Incidentally, it becomes increasingly apparent that this will require some very precise coding for simply picking up the parts after their spawning.
The arm is primarily mobilised by a pair of hydraulics and a wheel mount base. A second forearm allows the arm to extend to almost three times the length of a single arm plate length at full extension (That is, the entire arm aligned straight and with the second forearm fully extended). The hydraulic controls are presently located near their associated hydraulics because that should prove easiest for programming, but they could be placed elsewhere.
Overall, the arm has some limitations, namely in the area of fine manouvering and dexterity, but should be able to reach most of the operating areas of the drones with relative ease for repairs.
Last edited by Lyinginbedmon; 03-27-2009 at 11:28 AM.
That's exactly what stool turrets do :P.
http://www.garrysmod.org/downloads/?a=view&id=18521
Tool Turrets, automate your construction - Facepunch
Last edited by Bobsymalone; 03-27-2009 at 03:14 PM.
I think the biggest problem with this is going to be devising a way for an MRTA to know that another MRTA is broken. I also think there would have to be some sort of central controller to coordinate repairs so that multiple bots don't try to repair the same thing at once (which would be kinda comical, seeing the "repaired" bot with something of a "prop tumor").
EDIT: I like your choice of name btw. God of the forge and of technology.
Last edited by emspike; 03-27-2009 at 03:39 AM.
Bookmarks