var/datum/action_controller/actions //See _setup.dm for interrupt and state definitions /datum/action_controller var/list/running = list() //Associative list of running actions, format: owner=list of action datums proc/hasAction(var/atom/owner, var/id) //has this mob an action of a given type running? if(running.Find(owner)) var/list/actions = running[owner] for(var/datum/action/A in actions) if(A.id == id) return 1 return 0 proc/stop_all(var/atom/owner) //Interrupts all actions of a given owner. if(running.Find(owner)) for(var/datum/action/A in running[owner]) A.interrupt(INTERRUPT_ALWAYS) return proc/stop(var/datum/action/A, var/atom/owner) //Manually interrupts a given action of a given owner. if(running.Find(owner)) var/list/actions = running[owner] if(actions.Find(A)) A.interrupt(INTERRUPT_ALWAYS) return proc/stopId(var/id, var/atom/owner) //Manually interrupts a given action id of a given owner. if(running.Find(owner)) var/list/actions = running[owner] for(var/datum/action/A in actions) if(A.id == id) A.interrupt(INTERRUPT_ALWAYS) return proc/start(var/datum/action/A, var/atom/owner) //Starts a new action. if(!running.Find(owner)) running.Add(owner) running[owner] = list(A) else interrupt(owner, INTERRUPT_ACTION) running[owner] += A A.owner = owner A.started = world.time A.onStart() return A // cirr here, I added action ref to the return because I need it for AI stuff, thank you proc/interrupt(var/atom/owner, var/flag) //Is called by all kinds of things to check for action interrupts. if(running.Find(owner)) for(var/datum/action/A in running[owner]) A.interrupt(flag) return proc/process() //Handles the action countdowns, updates and deletions. for(var/X in running) for(var/datum/action/A in running[X]) if( ((A.duration >= 0 && world.time >= (A.started + A.duration)) && A.state == ACTIONSTATE_RUNNING) || A.state == ACTIONSTATE_FINISH) A.state = ACTIONSTATE_ENDED A.onEnd() //continue //If this is not commented out the deletion will take place the tick after the action ends. This will break things like objects being deleted onEnd with progressbars - the bars will be left behind. But it will look better for things that do not do this. if(A.state == ACTIONSTATE_DELETE) A.onDelete() running[X] -= A continue A.onUpdate() if(length(running[X]) == 0) running.Remove(X) return /datum/action var/atom/owner = null //Object that owns this action. var/duration = 1 //How long does this action take in ticks. var/interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION //When and how this action is interrupted. var/state = ACTIONSTATE_STOPPED //Current state of the action. var/started = -1 //world.time this action was started at var/id = "base" //Unique ID for this action. For when you want to remove actions by ID on a person. proc/interrupt(var/flag) //This is called by the default interrupt actions if(interrupt_flags & flag || flag == INTERRUPT_ALWAYS) state = ACTIONSTATE_INTERRUPTED onInterrupt(flag) return proc/onUpdate() //Called every tick this action is running. If you absolutely(!!!) have to you can do manual interrupt checking in here. Otherwise this is mostly used for drawing progress bars and shit. return proc/onInterrupt(var/flag = 0) //Called when the action fails / is interrupted. state = ACTIONSTATE_DELETE return proc/onStart() //Called when the action begins state = ACTIONSTATE_RUNNING return proc/onEnd() //Called when the action succesfully ends. state = ACTIONSTATE_DELETE return proc/onDelete() //Called when the action is complete and about to be deleted. Usable for cleanup and such. return proc/updateBar() // Updates the animations return /datum/action/bar //This subclass has a progressbar that attaches to the owner to show how long we need to wait. var/obj/actions/bar/bar var/obj/actions/border/border onStart() ..() var/atom/movable/A = owner if(owner != null) bar = unpool(/obj/actions/bar) bar.loc = owner.loc border = unpool(/obj/actions/border) border.loc = owner.loc bar.pixel_y = 5 bar.pixel_x = 0 border.pixel_y = 5 if (!islist(A.attached_objs)) A.attached_objs = list() A.attached_objs.Add(bar) A.attached_objs.Add(border) // this will absolutely obviously cause no problems. bar.color = "#4444FF" updateBar() onDelete() ..() var/atom/movable/A = owner if (owner != null && islist(A.attached_objs)) A.attached_objs.Remove(bar) A.attached_objs.Remove(border) SPAWN_DBG(5 DECI SECONDS) if (bar) pool(bar) bar = null if (border) pool(border) border = null onEnd() if (bar) bar.color = "#FFFFFF" animate( bar, color = "#00CC00", time = 2.5 , flags = ANIMATION_END_NOW) bar.transform = matrix() //Tiny cosmetic fix. Makes it so the bar is completely filled when the action ends. ..() onInterrupt(var/flag) if(state != ACTIONSTATE_DELETE) if (bar) updateBar(0) bar.color = "#FFFFFF" animate( bar, color = "#CC0000", time = 2.5 ) ..() onUpdate() updateBar() ..() updateBar(var/animate = 1) if (duration <= 0) return var/done = world.time - started // inflate it a little to stop it from hitting 100% "too early" var/fakeduration = duration + ((animate && done < duration) ? (world.tick_lag * 7) : 0) var/remain = max(0, fakeduration - done) var/complete = clamp(done / fakeduration, 0, 1) bar.transform = matrix(complete, 0, -15 * (1 - complete), 0, 1, 0) if (animate) animate( bar, transform = matrix(1, 0, 0, 0, 1, 0), time = remain ) else animate( bar, flags = ANIMATION_END_NOW ) /datum/action/bar/blob_health // WOW HACK onUpdate() var/obj/blob/B = owner if (!owner || !istype(owner) || !bar || !border) //Wire note: Fix for Cannot modify null.invisibility return if (B.health == B.health_max) border.invisibility = 101 bar.invisibility = 101 else border.invisibility = 0 bar.invisibility = 0 var/complete = B.health / B.health_max bar.color = "#00FF00" bar.transform = matrix(complete, 1, MATRIX_SCALE) bar.pixel_x = -nround( ((30 - (30 * complete)) / 2) ) /datum/action/bar/bullethell var/obj/actions/bar/shield_bar var/obj/actions/bar/armor_bar onStart() ..() var/atom/movable/A = owner if(owner != null) shield_bar = unpool(/obj/actions/bar) shield_bar.loc = owner.loc armor_bar = unpool(/obj/actions/bar) armor_bar.loc = owner.loc shield_bar.pixel_y = 5 armor_bar.pixel_y = 5 if (!islist(A.attached_objs)) A.attached_objs = list() A.attached_objs.Add(shield_bar) A.attached_objs.Add(armor_bar) shield_bar.layer = initial(shield_bar.layer) + 2 armor_bar.layer = initial(armor_bar.layer) + 1 onDelete() ..() shield_bar.invisibility = 0 armor_bar.invisibility = 0 bar.invisibility = 0 border.invisibility = 0 var/atom/movable/A = owner if (owner != null && islist(A.attached_objs)) A.attached_objs.Remove(shield_bar) A.attached_objs.Remove(armor_bar) pool(shield_bar) shield_bar = null pool(armor_bar) armor_bar = null onUpdate() var/obj/bullethell/B = owner if (!owner || !istype(owner)) return var/h_complete = B.health / B.max_health bar.color = "#00FF00" bar.transform = matrix(h_complete, 1, MATRIX_SCALE) bar.pixel_x = -nround( ((30 - (30 * h_complete)) / 2) ) if (B.max_armor && B.armor) armor_bar.invisibility = 0 var/a_complete = B.armor / B.max_armor armor_bar.color = "#FF8800" armor_bar.transform = matrix(a_complete, 1, MATRIX_SCALE) armor_bar.pixel_x = -nround( ((30 - (30 * a_complete)) / 2) ) else armor_bar.invisibility = 101 if (B.max_shield && B.shield) shield_bar.invisibility = 0 var/s_complete = B.shield / B.max_shield shield_bar.color = "#3333FF" shield_bar.transform = matrix(s_complete, 1, MATRIX_SCALE) shield_bar.pixel_x = -nround( ((30 - (30 * s_complete)) / 2) ) else shield_bar.invisibility = 101 /datum/action/bar/blob_replicator onUpdate() var/obj/blob/deposit/replicator/B = owner if (!owner) return if (!B.converting || (B.converting && !B.converting.maximum_volume)) border.invisibility = 101 bar.invisibility = 101 return else border.invisibility = 0 bar.invisibility = 0 var/complete = 1 - (B.converting.total_volume / B.converting.maximum_volume) bar.color = "#0000FF" bar.transform = matrix(complete, 1, MATRIX_SCALE) bar.pixel_x = -nround( ((30 - (30 * complete)) / 2) ) onDelete() bar.invisibility = 0 border.invisibility = 0 ..() /datum/action/bar/icon //Visible to everyone and has an icon. var/icon var/icon_state var/icon_y_off = 30 var/icon_x_off = 0 var/image/icon_image onStart() ..() if(icon && icon_state && owner) icon_image = image(icon, border ,icon_state, 10) icon_image.pixel_y = icon_y_off icon_image.pixel_x = icon_x_off icon_image.plane = PLANE_HUD icon_image.filters += filter(type="outline", size=0.5, color=rgb(255,255,255)) border.overlays += icon_image onDelete() if (bar) bar.overlays.Cut() if (icon_image) del(icon_image) ..() /datum/action/bar/icon/build duration = 30 var/obj/item/sheet/sheet var/objtype var/cost var/datum/material/mat var/amount var/objname var/callback = null var/obj/item/sheet/sheet2 // in case you need to pull from more than one sheet var/cost2 // same as above var/spot New(var/obj/item/sheet/csheet, var/cobjtype, var/ccost, var/datum/material/cmat, var/camount, var/cicon, var/cicon_state, var/cobjname, var/post_action_callback = null, var/obj/item/sheet/csheet2, var/ccost2, var/spot) ..() icon = cicon icon_state = cicon_state sheet = csheet objtype = cobjtype cost = ccost mat = cmat amount = camount objname = cobjname callback = post_action_callback src.spot = spot if (csheet2) sheet2 = csheet2 if (ccost2) cost2 = ccost2 onStart() ..() if(ishuman(owner)) var/mob/living/carbon/human/H = owner if(H.traitHolder.hasTrait("carpenter")) duration = round(duration / 2) owner.visible_message("[owner] begins assembling [objname]!") onEnd() ..() owner.visible_message("[owner] assembles [objname]!") var/obj/item/R = new objtype(get_turf(spot || owner)) R.setMaterial(mat) if (istype(R)) R.amount = amount R.dir = owner.dir sheet.consume_sheets(cost) if (sheet2 && cost2) sheet2.consume_sheets(cost2) logTheThing("station", owner, null, "builds [objname] (Material: [mat && istype(mat) && mat.mat_id ? "[mat.mat_id]" : "*UNKNOWN*"]) at [log_loc(owner)].") if (callback) call(callback)(src, R) /datum/action/bar/icon/cruiser_repair id = "genproc" interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION duration = 30 icon = 'icons/ui/actions.dmi' icon_state = "working" var/obj/machinery/cruiser_destroyable/repairing var/obj/item/using New(var/obj/machinery/cruiser_destroyable/D, var/obj/item/U, var/duration_i) ..() repairing = D using = U duration = duration_i onUpdate() ..() if(get_dist(owner, repairing) > 1 || repairing == null || owner == null || using == null) interrupt(INTERRUPT_ALWAYS) return var/mob/source = owner if(using != source.equipped()) interrupt(INTERRUPT_ALWAYS) onStart() ..() owner.visible_message("[owner] begins repairing [repairing]!") onEnd() ..() owner.visible_message("[owner] successfully repairs [repairing]!") repairing.adjustHealth(repairing.health_max) /datum/action/bar/private //This subclass is only visible to the owner of the action onStart() ..() bar.icon = null border.icon = null owner << bar.img owner << border.img onDelete() bar.icon = 'icons/ui/actions.dmi' border.icon = 'icons/ui/actions.dmi' del(bar.img) del(border.img) ..() /datum/action/bar/private/icon //Only visible to the owner and has a little icon on the bar. var/icon var/icon_state var/icon_y_off = 30 var/icon_x_off = 0 var/image/icon_image onStart() ..() if(icon && icon_state && owner) icon_image = image(icon ,owner,icon_state,10) icon_image.pixel_y = icon_y_off icon_image.pixel_x = icon_x_off icon_image.plane = PLANE_HUD icon_image.filters += filter(type="outline", size=0.5, color=rgb(255,255,255)) owner << icon_image onDelete() del(icon_image) ..() //ACTIONS /datum/action/bar/icon/genericProc //Calls a specific proc with the given arguments when the action succeeds. TBI id = "genproc" interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION icon = 'icons/mob/screen1.dmi' icon_state = "grabbed" /datum/action/bar/icon/otherItem//Putting items on or removing items from others. id = "otheritem" interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION icon = 'icons/mob/screen1.dmi' icon_state = "grabbed" var/mob/living/carbon/human/source //The person doing the action var/mob/living/carbon/human/target //The target of the action var/obj/item/item //The item if any. If theres no item, we tried to remove something from that slot instead of putting an item there. var/slot //The slot number New(var/Source, var/Target, var/Item, var/Slot, var/ExtraDuration = 0) source = Source target = Target item = Item slot = Slot if(item) if(item.duration_put > 0) duration = item.duration_put else duration = 45 else var/obj/item/I = target.get_slot(slot) if(I) if(I.duration_remove > 0) duration = I.duration_remove else duration = 25 duration += ExtraDuration ..() onStart() ..() target.add_fingerprint(source) // Added for forensics (Convair880). if (source.mob_flags & AT_GUNPOINT) for(var/obj/item/grab/gunpoint/G in source.grabbed_by) G.shoot() if(item) if(!target.can_equip(item, slot)) boutput(source, "[item] can not be put there.") interrupt(INTERRUPT_ALWAYS) return if(!isturf(target.loc)) boutput(source, "You can't put [item] on [target] when [(he_or_she(target))] is in [target.loc]!") interrupt(INTERRUPT_ALWAYS) return if(issilicon(source)) source.show_text("You can't put \the [item] on [target] when it's attached to you!", "red") interrupt(INTERRUPT_ALWAYS) return logTheThing("combat", source, target, "tries to put \an [item] on %target% at at [log_loc(target)].") for(var/mob/O in AIviewers(owner)) O.show_message("[source] tries to put [item] on [target]!", 1) else var/obj/item/I = target.get_slot(slot) if(!I) boutput(source, "There's nothing in that slot.") interrupt(INTERRUPT_ALWAYS) return if(!isturf(target.loc)) boutput(source, "You can't remove [I] from [target] when [(he_or_she(target))] is in [target.loc]!") interrupt(INTERRUPT_ALWAYS) return /* Some things use handle_other_remove to do stuff (ripping out staples, wiz hat probability, etc) should only be called once per removal. if(!I.handle_other_remove(source, target)) boutput(source, "[I] can not be removed.") interrupt(INTERRUPT_ALWAYS) return */ logTheThing("combat", source, target, "tries to remove \an [I] from %target% at [log_loc(target)].") for(var/mob/O in AIviewers(owner)) O.show_message("[source] tries to remove something from [target]!", 1) onEnd() ..() if(get_dist(source, target) > 1 || target == null || source == null) interrupt(INTERRUPT_ALWAYS) return var/obj/item/I = target.get_slot(slot) if(item) if(item == source.equipped() && !I) if(target.can_equip(item, slot)) logTheThing("combat", source, target, "successfully puts \an [item] on %target% at at [log_loc(target)].") for(var/mob/O in AIviewers(owner)) O.show_message("[source] puts [item] on [target]!", 1) source.u_equip(item) target.force_equip(item, slot) else if (I) //Wire: Fix for Cannot execute null.handle other remove(). if(I.handle_other_remove(source, target)) logTheThing("combat", source, target, "successfully removes \an [I] from %target% at [log_loc(target)].") for(var/mob/O in AIviewers(owner)) O.show_message("[source] removes [I] from [target]!", 1) // Re-added (Convair880). if (istype(I, /obj/item/mousetrap/)) var/obj/item/mousetrap/MT = I if (MT && MT.armed) for (var/mob/O in AIviewers(owner)) O.show_message("...and triggers it accidentally!", 1) MT.triggered(source, source.hand ? "l_hand" : "r_hand") else if (istype(I, /obj/item/mine)) var/obj/item/mine/M = I if (M.armed && M.used_up != 1) for (var/mob/O in AIviewers(owner)) O.show_message("...and triggers it accidentally!", 1) M.triggered(source) target.u_equip(I) I.set_loc(target.loc) I.dropped(target) I.layer = initial(I.layer) I.add_fingerprint(source) else boutput(source, "You fail to remove [I] from [target].") onUpdate() ..() if(get_dist(source, target) > 1 || target == null || source == null) interrupt(INTERRUPT_ALWAYS) return if(item) if(item != source.equipped() || target.get_slot(slot)) interrupt(INTERRUPT_ALWAYS) else if(!target.get_slot(slot=slot)) interrupt(INTERRUPT_ALWAYS) /datum/action/bar/icon/internalsOther //This is used when you try to set someones internals duration = 40 interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION id = "internalsother" icon = 'icons/obj/clothing/item_masks.dmi' icon_state = "breath" var/mob/living/carbon/human/target var/remove_internals New(Target) target = Target ..() onUpdate() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return onStart() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return for(var/mob/O in AIviewers(owner)) if(target.internal) O.show_message("[owner] attempts to remove [target]'s internals!", 1) remove_internals = 1 else O.show_message("[owner] attempts to set [target]'s internals!", 1) remove_internals = 0 onEnd() ..() if(owner && target && get_dist(owner, target) <= 1) if(remove_internals) target.internal.add_fingerprint(owner) for (var/obj/ability_button/tank_valve_toggle/T in target.internal.ability_buttons) T.icon_state = "airoff" target.internal = null for(var/mob/O in AIviewers(owner)) O.show_message("[owner] removes [target]'s internals!", 1) else if (!istype(target.wear_mask, /obj/item/clothing/mask)) interrupt(INTERRUPT_ALWAYS) return else if (istype(target.back, /obj/item/tank)) target.internal = target.back for (var/obj/ability_button/tank_valve_toggle/T in target.internal.ability_buttons) T.icon_state = "airon" for(var/mob/M in AIviewers(target, 1)) M.show_message(text("[] is now running on internals.", src.target), 1) target.internal.add_fingerprint(owner) /datum/action/bar/icon/handcuffSet //This is used when you try to handcuff someone. duration = 40 interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION id = "handcuffsset" icon = 'icons/obj/items.dmi' icon_state = "handcuff" var/mob/living/carbon/human/target var/obj/item/handcuffs/cuffs New(Target, Cuffs) target = Target cuffs = Cuffs ..() onUpdate() ..() if(get_dist(owner, target) > 1 || target == null || owner == null || cuffs == null) interrupt(INTERRUPT_ALWAYS) return if(target.handcuffed) interrupt(INTERRUPT_ALWAYS) return onStart() ..() if(get_dist(owner, target) > 1 || target == null || owner == null || cuffs == null) interrupt(INTERRUPT_ALWAYS) return if(ishuman(owner)) var/mob/living/carbon/human/H = owner if(H.traitHolder.hasTrait("training_security")) duration = round(duration / 2) for(var/mob/O in AIviewers(owner)) O.show_message("[owner] attempts to handcuff [target]!", 1) onEnd() ..() var/mob/ownerMob = owner if(owner && ownerMob && target && cuffs && !target.handcuffed && cuffs == ownerMob.equipped() && get_dist(owner, target) <= 1) var/obj/item/handcuffs/cuffs2 if (issilicon(ownerMob)) cuffs2 = new /obj/item/handcuffs else if (cuffs.amount >= 2) cuffs2 = new /obj/item/handcuffs/tape cuffs.amount-- boutput(ownerMob, "The [cuffs.name] now has [cuffs.amount] lengths of [istype(cuffs, /obj/item/handcuffs/tape_roll) ? "tape" : "ziptie"] left.") else if (cuffs.amount == 1 && cuffs.delete_on_last_use == 1) cuffs2 = new /obj/item/handcuffs/tape ownerMob.u_equip(cuffs) boutput(ownerMob, "You used up the remaining length of [istype(cuffs, /obj/item/handcuffs/tape_roll) ? "tape" : "ziptie"].") qdel(cuffs) else ownerMob.u_equip(cuffs) logTheThing("combat", ownerMob, target, "handcuffs %target% with [cuffs2 ? "[cuffs2]" : "[cuffs]"] at [log_loc(ownerMob)].") if (cuffs2 && istype(cuffs2)) cuffs2.set_loc(target) target.handcuffed = cuffs2 else cuffs.set_loc(target) target.handcuffed = cuffs target.drop_from_slot(target.r_hand) target.drop_from_slot(target.l_hand) target.drop_juggle() target.update_clothing() target.setStatus("handcuffed", duration = null) for(var/mob/O in AIviewers(ownerMob)) O.show_message("[owner] handcuffs [target]!", 1) /datum/action/bar/icon/handcuffRemovalOther //This is used when you try to remove someone elses handcuffs. duration = 70 interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION id = "handcuffsother" icon = 'icons/obj/items.dmi' icon_state = "handcuff" var/mob/living/carbon/human/target New(Target) target = Target ..() onUpdate() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return if(!target.handcuffed) interrupt(INTERRUPT_ALWAYS) return onStart() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return for(var/mob/O in AIviewers(owner)) O.show_message("[owner] attempts to remove [target]'s handcuffs!", 1) onEnd() ..() if(owner && target && target.handcuffed) var/mob/living/carbon/human/H = target H.handcuffed:set_loc(H.loc) H.handcuffed.unequipped(H) H.handcuffed = null H.update_clothing() for(var/mob/O in AIviewers(H)) O.show_message("[owner] manages to remove [target]'s handcuffs!", 1) /datum/action/bar/private/icon/handcuffRemoval //This is used when you try to resist out of handcuffs. duration = 600 interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION id = "handcuffs" icon = 'icons/obj/items.dmi' icon_state = "handcuff" New(var/dur) duration = dur ..() onStart() ..() for(var/mob/O in AIviewers(owner)) O.show_message(text("[] attempts to remove the handcuffs!", owner), 1) onInterrupt(var/flag) ..() boutput(owner, "Your attempt to remove your handcuffs was interrupted!") onEnd() ..() if(owner != null && ishuman(owner) && owner:handcuffed) var/mob/living/carbon/human/H = owner H.handcuffed:set_loc(H.loc) H.handcuffed.unequipped(H) H.handcuffed = null H.update_clothing() if (H.handcuffed) H.handcuffed.layer = initial(H.handcuffed.layer) for(var/mob/O in AIviewers(H)) O.show_message("[H] manages to remove the handcuffs!", 1) boutput(H, "You successfully remove your handcuffs.") /datum/action/bar/private/icon/shackles_removal // Resisting out of shackles (Convair880). duration = 450 interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION id = "shackles" icon = 'icons/obj/clothing/item_shoes.dmi' icon_state = "orange1" New(var/dur) duration = dur ..() onStart() ..() for(var/mob/O in AIviewers(owner)) O.show_message(text("[] attempts to remove the shackles!", owner), 1) onInterrupt(var/flag) ..() boutput(owner, "Your attempt to remove the shackles was interrupted!") onEnd() ..() if (owner != null && ishuman(owner)) var/mob/living/carbon/human/H = owner if (H.shoes && H.shoes.chained) var/obj/item/clothing/shoes/SH = H.shoes H.u_equip(SH) SH.set_loc(H.loc) H.update_clothing() if (SH) SH.layer = initial(SH.layer) for(var/mob/O in AIviewers(H)) O.show_message("[H] manages to remove the shackles!", 1) H.show_text("You successfully remove the shackles.", "blue") //CLASSES & OBJS /obj/actions //These objects are mostly used for the attached_objs var on mobs to attach progressbars to mobs. icon = 'icons/ui/actions.dmi' anchored = 1 density = 0 opacity = 0 layer = 5 name = "" desc = "" mouse_opacity = 0 /obj/actions/bar icon_state = "bar" layer = 101 plane = PLANE_HUD + 1 var/image/img New() img = image('icons/ui/actions.dmi',src,"bar",6) unpooled() img = image('icons/ui/actions.dmi',src,"bar",6) icon = initial(icon) icon_state = initial(icon_state) pooled() loc = null attached_objs = list() overlays.len = 0 /obj/actions/border layer = 100 icon_state = "border" plane = PLANE_HUD + 1 var/image/img New() img = image('icons/ui/actions.dmi',src,"border",5) unpooled() img = image('icons/ui/actions.dmi',src,"border",5) icon = initial(icon) icon_state = initial(icon_state) pooled() loc = null attached_objs = list() overlays.len = 0 //Use this to start the action //actions.start(new/datum/action/bar/private/icon/magPicker(item, picker), usr) /datum/action/bar/private/icon/magPicker duration = 30 //How long does this action take in ticks. interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION id = "magpicker" icon = 'icons/obj/items.dmi' //In these two vars you can define an icon you want to have on your little progress bar. icon_state = "magtractor-small" var/obj/item/target = null //This will contain the object we are trying to pick up. var/obj/item/magtractor/picker = null //This is the magpicker. New(Target, Picker) target = Target picker = Picker ..() onUpdate() //check for special conditions that could interrupt the picking-up here. ..() if(get_dist(owner, target) > 1 || picker == null || target == null || owner == null) //If the thing is suddenly out of range, interrupt the action. Also interrupt if the user or the item disappears. interrupt(INTERRUPT_ALWAYS) return onStart() ..() if(get_dist(owner, target) > 1 || picker == null || target == null || owner == null || picker.working) //If the thing is out of range, interrupt the action. Also interrupt if the user or the item disappears. interrupt(INTERRUPT_ALWAYS) return else picker.working = 1 playsound(picker.loc, "sound/machines/whistlebeep.ogg", 50, 1) out(owner, "\The [picker.name] starts to pick up \the [target].") if (picker.highpower && owner:cell) var/hpm_cost = 25 * (target.w_class * 2 + 1) // Buff HPM by making it pick things up faster, at the expense of cell charge // only allow it if more than double that power remains to keep it from bottoming out if (owner:cell.charge >= hpm_cost * 2) duration /= 3 owner:cell.use(hpm_cost) onInterrupt(var/flag) //They did something else while picking it up. I guess you dont have to do anything here unless you want to. ..() picker.working = 0 onEnd() ..() //Shove the item into the picker here!!! if (ismob(target.loc)) var/mob/M = target.loc M.u_equip(target) picker.pickupItem(target, owner) actions.start(new/datum/action/magPickerHold(picker, picker.highpower), owner) /datum/action/magPickerHold duration = 30 interrupt_flags = INTERRUPT_MOVE | INTERRUPT_STUNNED id = "magpickerhold" var/obj/item/magtractor/picker = null //This is the magpicker. New(Picker, hpm) if (hpm) src.interrupt_flags &= ~INTERRUPT_MOVE picker = Picker picker.holdAction = src ..() onUpdate() //Again, check here for special conditions that are not normally handled in here. You probably dont need to do anything. ..() if(picker == null || owner == null) //Interrupt if the user or the magpicker disappears. interrupt(INTERRUPT_ALWAYS) return onStart() ..() state = ACTIONSTATE_INFINITE //We can hold it indefinitely unless we move. if(picker == null || owner == null) //Interrupt if the user or the magpicker dont exist. interrupt(INTERRUPT_ALWAYS) return onEnd() ..() if (picker) picker.dropItem() onInterrupt(var/flag) ..() if (picker) picker.dropItem() /datum/action/bar/icon/butcher_living_critter //Used when butchering a player-controlled critter duration = 120 interrupt_flags = INTERRUPT_MOVE | INTERRUPT_STUNNED id = "butcherlivingcritter" var/mob/living/critter/target New(Target) target = Target ..() onUpdate() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return onStart() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return for(var/mob/O in AIviewers(owner)) O.show_message("[owner] begins to butcher [target].", 1) onEnd() ..() if(owner && target) target.butcher(owner) for(var/mob/O in AIviewers(owner)) O.show_message("[owner] butchers [target].[target.butcherable == 2 ? "WHAT A MONSTER" : null]", 1) /datum/action/bar/icon/rev_flash duration = 13 SECONDS interrupt_flags = INTERRUPT_MOVE | INTERRUPT_STUNNED id = "rev_flash" icon = 'icons/ui/actions.dmi' icon_state = "rev_imp" var/mob/living/target var/obj/item/device/flash/revolution/flash New(Flash, Target) flash = Flash target = Target ..() onUpdate() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return onStart() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return onEnd() ..() if(owner && target) if (ishuman(target)) var/mob/living/carbon/human/H = target var/obj/item/implant/antirev/found_imp = (locate(/obj/item/implant/antirev) in H.implant) if (found_imp) found_imp.on_remove(target) H.implant.Remove(found_imp) qdel(found_imp) playsound(target.loc, 'sound/impact_sounds/Crystal_Shatter_1.ogg', 50, 0.1, 0, 0.9) target.visible_message("The loyalty implant inside [target] shatters into one million pieces!") flash.flash_mob(target, owner) /datum/action/bar/icon/mop_thing duration = 30 interrupt_flags = INTERRUPT_STUNNED id = "mop_thing" icon = 'icons/obj/janitor.dmi' //In these two vars you can define an icon you want to have on your little progress bar. icon_state = "mop" var/atom/target var/obj/item/mop/mop New(Mop, Target) mop = Mop target = Target duration = istype(target,/obj/fluid) ? 0 : 10 ..() onUpdate() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return onStart() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return onEnd() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return if(owner && target) mop.clean(target, owner) /datum/action/bar/private/spy_steal //Used when a spy tries to steal a large object duration = 30 interrupt_flags = INTERRUPT_MOVE | INTERRUPT_STUNNED id = "spy_steal" var/atom/target var/obj/item/uplink/integrated/pda/spy/uplink New(Target, Uplink) target = Target uplink = Uplink ..() onUpdate() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return onStart() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return playsound(owner.loc, "sound/machines/click.ogg", 60, 1) onEnd() ..() if(owner && target && uplink) uplink.try_deliver(target, owner) //DEBUG STUFF /datum/action/bar/private/bombtest duration = 100 id = "bombtest" onEnd() ..() qdel(owner) /obj/bombtest name = "large cartoon bomb" desc = "It looks like it's gonna blow." icon = 'icons/obj/weapons.dmi' icon_state = "dumb_bomb" density = 1 New() actions.start(new/datum/action/bar/private/bombtest(), src) ..() /datum/action/fire_roll //constant rolling duration = -1 interrupt_flags = INTERRUPT_STUNNED id = "fire_roll" var/mob/living/M = 0 var/sfx_interval = 5 var/sfx_count = 0 var/pixely = 0 var/up = 1 New() ..() onUpdate() ..() if (M && M.resting && !M.stat && M.getStatusDuration("burning")) M.update_burning(-1.2) M.dir = turn(M.dir,up ? -90 : 90) pixely += up ? 1 : -1 if (pixely != CLAMP(pixely, -5,5)) up = !up M.pixel_y = pixely sfx_count += 1 if (sfx_count >= sfx_interval) playsound(M.loc, 'sound/impact_sounds/Generic_Shove_1.ogg', 50, 1, 0 , 0.7) sfx_count = 0 var/turf/T = get_turf(M) if (T.active_liquid) T.active_liquid.HasEntered(M, T) else interrupt(INTERRUPT_ALWAYS) onStart() ..() M = owner if (!M.resting) M.resting = 1 var/mob/living/carbon/human/H = M if (istype(H)) H.hud.update_resting() for (var/mob/O in AIviewers(M)) O.show_message("[M] throws themselves onto the floor!", 1, group = "resist") else for (var/mob/O in AIviewers(M)) O.show_message("[M] rolls around on the floor, trying to extinguish the flames.", 1, group = "resist") M.update_burning(-1.5) M.unlock_medal("Through the fire and flames", 1) playsound(M.loc, 'sound/impact_sounds/Generic_Shove_1.ogg', 50, 1, 0 , 0.7) onInterrupt(var/flag) ..() if (M) M.pixel_y = 0 onEnd() ..() if (M) M.pixel_y = 0 /datum/action/bar/private/icon/pickup //Delayed pickup, used for mousedrags to prevent 'auto clicky' exploits but allot us to pickup with mousedrag as a possibel action duration = 10 interrupt_flags = INTERRUPT_MOVE | INTERRUPT_STUNNED id = "pickup" var/obj/item/target icon = 'icons/ui/actions.dmi' icon_state = "pickup" New(Target) target = Target ..() onUpdate() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return onStart() ..() if(get_dist(owner, target) > 1 || target == null || owner == null) interrupt(INTERRUPT_ALWAYS) return onEnd() ..() target.pick_up_by(owner) then_hud_click var/atom/over_object var/params New(Target, Over, Parameters) target = Target over_object = Over params = Parameters ..() onEnd() ..() target.try_equip_to_inventory_object(owner, over_object, params)