diff --git a/code/__DEFINES/melee.dm b/code/__DEFINES/melee.dm
new file mode 100644
index 0000000000..cb4a433211
--- /dev/null
+++ b/code/__DEFINES/melee.dm
@@ -0,0 +1,10 @@
+//Martial arts defines
+
+#define MARTIALART_BOXING "boxing"
+#define MARTIALART_WRESTLING "wrestling"
+#define MARTIALART_SLEEPINGCARP "sleeping carp"
+#define MARTIALART_PSYCHOBRAWL "psychotic brawling"
+#define MARTIALART_MUSHPUNCH "mushroom punch"
+#define MARTIALART_KRAVMAGA "krav maga"
+#define MARTIALART_CQC "CQC"
+#define MARTIALART_PLASMAFIST "plasma fist"
\ No newline at end of file
diff --git a/code/datums/martial.dm b/code/datums/martial.dm
index ae8f92a342..d119759efc 100644
--- a/code/datums/martial.dm
+++ b/code/datums/martial.dm
@@ -2,6 +2,7 @@
var/name = "Martial Art"
var/streak = ""
var/max_streak_length = 6
+ var/id = "" //ID, used by mind/has_martialartcode\game\objects\items\granters.dm:345:error: user.mind.has_martialart: undefined proccode\game\objects\items\granters.dm:345:error: user.mind.has_martialart: undefined proccode\game\objects\items\granters.dm:345:error: user.mind.has_martialart: undefined proccode\game\objects\items\granters.dm:345:error: user.mind.has_martialart: undefined proccode\game\objects\items\granters.dm:345:error: user.mind.has_martialart: undefined proc
var/current_target
var/datum/martial_art/base // The permanent style. This will be null unless the martial art is temporary
var/deflection_chance = 0 //Chance to deflect projectiles
diff --git a/code/datums/martial/boxing.dm b/code/datums/martial/boxing.dm
index c93fc47f2b..7399528e1c 100644
--- a/code/datums/martial/boxing.dm
+++ b/code/datums/martial/boxing.dm
@@ -1,5 +1,6 @@
/datum/martial_art/boxing
name = "Boxing"
+ id = MARTIALART_BOXING
/datum/martial_art/boxing/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
to_chat(A, "Can't disarm while boxing!")
diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm
index 55cd4a3f7a..71545476ff 100644
--- a/code/datums/martial/cqc.dm
+++ b/code/datums/martial/cqc.dm
@@ -6,6 +6,7 @@
/datum/martial_art/cqc
name = "CQC"
+ id = MARTIALART_CQC
help_verb = /mob/living/carbon/human/proc/CQC_help
block_chance = 75
var/just_a_cook = FALSE
diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm
index 2a2e69bea5..9e40a5a3dc 100644
--- a/code/datums/martial/krav_maga.dm
+++ b/code/datums/martial/krav_maga.dm
@@ -1,5 +1,6 @@
/datum/martial_art/krav_maga
name = "Krav Maga"
+ id = MARTIALART_KRAVMAGA
var/datum/action/neck_chop/neckchop = new/datum/action/neck_chop()
var/datum/action/leg_sweep/legsweep = new/datum/action/leg_sweep()
var/datum/action/lung_punch/lungpunch = new/datum/action/lung_punch()
diff --git a/code/datums/martial/mushpunch.dm b/code/datums/martial/mushpunch.dm
index 33d5bb51bf..1ef7734771 100644
--- a/code/datums/martial/mushpunch.dm
+++ b/code/datums/martial/mushpunch.dm
@@ -1,5 +1,6 @@
/datum/martial_art/mushpunch
name = "Mushroom Punch"
+ id = MARTIALART_MUSHPUNCH
/datum/martial_art/mushpunch/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/atk_verb
diff --git a/code/datums/martial/plasma_fist.dm b/code/datums/martial/plasma_fist.dm
index f540dc0783..e38a011db0 100644
--- a/code/datums/martial/plasma_fist.dm
+++ b/code/datums/martial/plasma_fist.dm
@@ -4,6 +4,7 @@
/datum/martial_art/plasma_fist
name = "Plasma Fist"
+ id = MARTIALART_PLASMAFIST
help_verb = /mob/living/carbon/human/proc/plasma_fist_help
diff --git a/code/datums/martial/psychotic_brawl.dm b/code/datums/martial/psychotic_brawl.dm
index 1cb18f903f..8f1a33a8b3 100644
--- a/code/datums/martial/psychotic_brawl.dm
+++ b/code/datums/martial/psychotic_brawl.dm
@@ -1,5 +1,6 @@
/datum/martial_art/psychotic_brawling
name = "Psychotic Brawling"
+ id = MARTIALART_PSYCHOBRAWL
/datum/martial_art/psychotic_brawling/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
return psycho_attack(A,D)
diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm
index 5f19c37b99..e205d7a435 100644
--- a/code/datums/martial/sleeping_carp.dm
+++ b/code/datums/martial/sleeping_carp.dm
@@ -6,6 +6,7 @@
/datum/martial_art/the_sleeping_carp
name = "The Sleeping Carp"
+ id = MARTIALART_SLEEPINGCARP
deflection_chance = 100
reroute_deflection = TRUE
no_guns = TRUE
diff --git a/code/datums/martial/wrestling.dm b/code/datums/martial/wrestling.dm
index e57edf9fb2..e07fa27ef5 100644
--- a/code/datums/martial/wrestling.dm
+++ b/code/datums/martial/wrestling.dm
@@ -10,6 +10,7 @@
/datum/martial_art/wrestling
name = "Wrestling"
+ id = MARTIALART_WRESTLING
var/datum/action/slam/slam = new/datum/action/slam()
var/datum/action/throw_wrassle/throw_wrassle = new/datum/action/throw_wrassle()
var/datum/action/kick/kick = new/datum/action/kick()
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 51fc6c54f6..8e61801e15 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -64,6 +64,8 @@
var/force_escaped = FALSE // Set by Into The Sunset command of the shuttle manipulator
+ var/list/learned_recipes //List of learned recipe TYPES.
+
/datum/mind/New(var/key)
src.key = key
soulOwner = src
@@ -779,6 +781,11 @@
mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist)
mind.active = 1 //indicates that the mind is currently synced with a client
+/datum/mind/proc/has_martialart(var/string)
+ if(martial_art && martial_art.id == string)
+ return martial_art
+ return FALSE
+
/mob/dead/new_player/sync_mind()
return
diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm
index 21f6961e5d..686c6fd511 100644
--- a/code/game/objects/items/granters.dm
+++ b/code/game/objects/items/granters.dm
@@ -1,4 +1,3 @@
-
///books that teach things (intrinsic actions like bar flinging, spells like fireball or smoke, or martial arts)///
/obj/item/book/granter
@@ -13,19 +12,50 @@
/obj/item/book/granter/proc/turn_page(mob/user)
playsound(user, pick('sound/effects/pageturn1.ogg','sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg'), 30, 1)
if(do_after(user,50, user))
- to_chat(user, "[pick(remarks)]")
+ if(remarks.len)
+ to_chat(user, "[pick(remarks)]")
+ else
+ to_chat(user, "You keep reading...")
return TRUE
return FALSE
/obj/item/book/granter/proc/recoil(mob/user) //nothing so some books can just return
+/obj/item/book/granter/proc/already_known(mob/user)
+ return FALSE
+
+/obj/item/book/granter/proc/on_reading_start(mob/user)
+ to_chat(user, "You start reading [name]...")
+
+/obj/item/book/granter/proc/on_reading_stopped(mob/user)
+ to_chat(user, "You stop reading...")
+
+/obj/item/book/granter/proc/on_reading_finished(mob/user)
+ to_chat(user, "You finish reading [name]!")
+
/obj/item/book/granter/proc/onlearned(mob/user)
used = TRUE
+
/obj/item/book/granter/attack_self(mob/user)
- if(reading == TRUE)
+ if(reading)
to_chat(user, "You're already reading this!")
return FALSE
+ if(already_known(user))
+ return FALSE
+ if(used && oneuse)
+ recoil(user)
+ else
+ on_reading_start(user)
+ reading = TRUE
+ for(var/i=1, i<=pages_to_mastery, i++)
+ if(!turn_page(user))
+ on_reading_stopped()
+ reading = FALSE
+ return
+ if(do_after(user,50, user))
+ on_reading_finished(user)
+ reading = FALSE
return TRUE
///ACTION BUTTONS///
@@ -34,33 +64,23 @@
var/granted_action
var/actionname = "catching bugs" //might not seem needed but this makes it so you can safely name action buttons toggle this or that without it fucking up the granter, also caps
-/obj/item/book/granter/action/attack_self(mob/user)
- . = ..()
- if(!.)
- return
+/obj/item/book/granter/action/already_known(mob/user)
if(!granted_action)
- return
- var/datum/action/G = new granted_action
+ return TRUE
for(var/datum/action/A in user.actions)
- if(A.type == G.type)
+ if(A.type == granted_action)
to_chat(user, "You already know all about [actionname].")
- qdel(G)
- return
- if(used == TRUE && oneuse == TRUE)
- recoil(user)
- else
- to_chat(user, "You start reading about [actionname]...")
- reading = TRUE
- for(var/i=1, i<=pages_to_mastery, i++)
- if(!turn_page(user))
- to_chat(user, "You stop reading...")
- reading = FALSE
- qdel(G)
- return
- if(do_after(user,50, user))
- to_chat(user, "You feel like you've got a good handle on [actionname]!")
- G.Grant(user)
- reading = FALSE
+ return TRUE
+ return FALSE
+
+/obj/item/book/granter/action/on_reading_start(mob/user)
+ to_chat(user, "You start reading about [actionname]...")
+
+/obj/item/book/granter/action/on_reading_finished(mob/user)
+ to_chat(user, "You feel like you've got a good handle on [actionname]!")
+ var/datum/action/G = new granted_action
+ G.Grant(user)
+ onlearned(user)
/obj/item/book/granter/action/drink_fling
granted_action = /datum/action/innate/drink_fling
@@ -120,38 +140,28 @@
var/spell
var/spellname = "conjure bugs"
-/obj/item/book/granter/spell/attack_self(mob/user)
- . = ..()
- if(!.)
- return
+/obj/item/book/granter/spell/already_known(mob/user)
if(!spell)
- return
- var/obj/effect/proc_holder/spell/S = new spell
+ return TRUE
for(var/obj/effect/proc_holder/spell/knownspell in user.mind.spell_list)
- if(knownspell.type == S.type)
+ if(knownspell.type == spell)
if(user.mind)
if(iswizard(user))
- to_chat(user,"You're already far more versed in this spell than this flimsy howto book can provide.")
+ to_chat(user,"You're already far more versed in this spell than this flimsy how-to book can provide.")
else
to_chat(user,"You've already read this one.")
- return
- if(used == TRUE && oneuse == TRUE)
- recoil(user)
- else
- to_chat(user, "You start reading about casting [spellname]...")
- reading = TRUE
- for(var/i=1, i<=pages_to_mastery, i++)
- if(!turn_page(user))
- to_chat(user, "You stop reading...")
- reading = FALSE
- qdel(S)
- return
- if(do_after(user,50, user))
- to_chat(user, "You feel like you've experienced enough to cast [spellname]!")
- user.mind.AddSpell(S)
- user.log_message("learned the spell [spellname] ([S])", LOG_ATTACK, color="orange")
- onlearned(user)
- reading = FALSE
+ return TRUE
+ return FALSE
+
+/obj/item/book/granter/spell/on_reading_start(mob/user)
+ to_chat(user, "You start reading about casting [spellname]...")
+
+/obj/item/book/granter/spell/on_reading_finished(mob/user)
+ to_chat(user, "You feel like you've experienced enough to cast [spellname]!")
+ var/obj/effect/proc_holder/spell/S = new spell
+ user.mind.AddSpell(S)
+ user.log_message("learned the spell [spellname] ([S])", LOG_ATTACK, color="orange")
+ onlearned(user)
/obj/item/book/granter/spell/recoil(mob/user)
user.visible_message("[src] glows in a black light!")
@@ -280,7 +290,8 @@
if(ishuman(user))
to_chat(user,"HORSIE HAS RISEN")
var/obj/item/clothing/magichead = new /obj/item/clothing/mask/horsehead/cursed(user.drop_location())
- user.dropItemToGround(user.wear_mask, TRUE)
+ if(!user.dropItemToGround(user.wear_mask))
+ qdel(user.wear_mask)
user.equip_to_slot_if_possible(magichead, SLOT_WEAR_MASK, TRUE, TRUE)
qdel(src)
else
@@ -327,35 +338,24 @@
var/martialname = "bug jitsu"
var/greet = "You feel like you have mastered the art in breaking code. Nice work, jackass."
-/obj/item/book/granter/martial/attack_self(mob/user)
- . = ..()
- if(!.)
- return
+/obj/item/book/granter/martial/already_known(mob/user)
if(!martial)
- return
+ return TRUE
+ var/datum/martial_art/MA = martial
+ if(user.mind.has_martialart(initial(MA.id)))
+ to_chat(user,"You already know [martialname]!")
+ return TRUE
+ return FALSE
+
+/obj/item/book/granter/martial/on_reading_start(mob/user)
+ to_chat(user, "You start reading about [martialname]...")
+
+/obj/item/book/granter/martial/on_reading_finished(mob/user)
+ to_chat(user, "[greet]")
var/datum/martial_art/MA = new martial
- if(user.mind.martial_art)
- for(var/datum/martial_art/knownmartial in user.mind.martial_art)
- if(knownmartial.type == MA.type)
- to_chat(user,"You already know [martialname]!")
- return
- if(used == TRUE && oneuse == TRUE)
- recoil(user)
- else
- to_chat(user, "You start reading about [martialname]...")
- reading = TRUE
- for(var/i=1, i<=pages_to_mastery, i++)
- if(!turn_page(user))
- to_chat(user, "You stop reading...")
- reading = FALSE
- qdel(MA)
- return
- if(do_after(user,50, user))
- to_chat(user, "[greet]")
- MA.teach(user)
- user.log_message("learned the martial art [martialname] ([MA])", LOG_ATTACK, color="orange")
- onlearned(user)
- reading = FALSE
+ MA.teach(user)
+ user.log_message("learned the martial art [martialname] ([MA])", LOG_ATTACK, color="orange")
+ onlearned(user)
/obj/item/book/granter/martial/cqc
martial = /datum/martial_art/cqc
@@ -416,3 +416,18 @@
icon_state = "blankscroll"
// I did not include mushpunch's grant, it is not a book and the item does it just fine.
+
+
+//Crafting Recipe books
+
+/obj/item/book/granter/crafting_recipe
+ var/list/crafting_recipe_types = list()
+
+/obj/item/book/granter/crafting_recipe/on_reading_finished(mob/user)
+ . = ..()
+ if(!user.mind)
+ return
+ for(var/crafting_recipe_type in crafting_recipe_types)
+ var/datum/crafting_recipe/R = crafting_recipe_type
+ user.mind.teach_crafting_recipe(crafting_recipe_type)
+ to_chat(user,"You learned how to make [initial(R.name)].")
\ No newline at end of file
diff --git a/code/game/objects/items/implants/implant_krav_maga.dm b/code/game/objects/items/implants/implant_krav_maga.dm
index 3a751ecd0e..373658b386 100644
--- a/code/game/objects/items/implants/implant_krav_maga.dm
+++ b/code/game/objects/items/implants/implant_krav_maga.dm
@@ -21,7 +21,7 @@
return
if(!H.mind)
return
- if(istype(H.mind.martial_art, /datum/martial_art/krav_maga))
+ if(H.mind.has_martialart(MARTIALART_KRAVMAGA))
style.remove(H)
else
style.teach(H,1)
diff --git a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm
index 3e96512bb8..0fb46c3e46 100644
--- a/code/modules/crafting/craft.dm
+++ b/code/modules/crafting/craft.dm
@@ -317,6 +317,8 @@
var/list/cant_craft = list()
for(var/rec in GLOB.crafting_recipes)
var/datum/crafting_recipe/R = rec
+ if(!R.always_availible && !(R.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this.
+ continue
if((R.category != cur_category) || (R.subcategory != cur_subcategory))
continue
if(check_contents(R, surroundings))
@@ -431,3 +433,10 @@
data["tool_text"] = tool_text
return data
+
+//Mind helpers
+
+/datum/mind/proc/teach_crafting_recipe(R)
+ if(!learned_recipes)
+ learned_recipes = list()
+ learned_recipes |= R
\ No newline at end of file
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index f0665682a9..3c614c6a9e 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -9,6 +9,7 @@
var/chem_catalysts[] = list() //like tools but for reagents
var/category = CAT_NONE //where it shows up in the crafting UI
var/subcategory = CAT_NONE
+ var/always_availible = TRUE //Set to FALSE if it needs to be learned first.
/datum/crafting_recipe/pin_removal
name = "Pin Removal"
diff --git a/tgstation.dme b/tgstation.dme
index 24477d885b..7e7b5a00c9 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -62,6 +62,7 @@
#include "code\__DEFINES\maths.dm"
#include "code\__DEFINES\MC.dm"
#include "code\__DEFINES\medal.dm"
+#include "code\__DEFINES\melee.dm"
#include "code\__DEFINES\menu.dm"
#include "code\__DEFINES\misc.dm"
#include "code\__DEFINES\mobs.dm"