diff --git a/config.lua b/config.lua
index 5803160f..798e1f52 100644
--- a/config.lua
+++ b/config.lua
@@ -436,6 +436,11 @@ global.config = {
     },
     spidertron_group_control = {
         enabled = true
+    },
+    donator = {
+        donator_perks = {
+            enabled = true
+        }
     }
 }
 
diff --git a/features/donator.lua b/features/donator.lua
index 56c2557a..05491fb7 100644
--- a/features/donator.lua
+++ b/features/donator.lua
@@ -6,27 +6,62 @@ local Token = require 'utils.token'
 local table = require 'utils.table'
 local Global = require 'utils.global'
 local Task = require 'utils.task'
+local DonatorPerks = require 'resources.donator_perks'
 
 local concat = table.concat
 local remove = table.remove
 local set_data = Server.set_data
 local random = math.random
+local config = global.config.donator
 
 local donator_data_set = 'donators'
-
 local donators = {} -- global register
+local donator_perks_perm = {} -- buffs to the force that will remain even when the donator is offline (T5)
+local donator_perks_temp = {} -- buffs to the force that are only applied while the donator is online (T2, T3, T4)
+local donator_tiers = {
+                        [1] = {name = "[img=item.wood]", count = 0, max = 10}, -- keeps track of how many have been applied so we can limit the amount of donators contributing to buffs
+                        [2] = {name = "[img=item.coal]", count = 0, max = 10},
+                        [3] = {name = "[img=item.solid-fuel]", count = 0, max = 10},
+                        [4] = {name = "[img=item.rocket-fuel]", count = 0, max = 10},
+                        [5] = {name = "[img=item.nuclear-fuel]", count = 0, max = 6}
+                    }
 
 Global.register(
     {
-        donators = donators
+        donators = donators,
+        donator_perks_perm = donator_perks_perm,
+        donator_perks_temp = donator_perks_temp,
+        donator_tiers = donator_tiers
     },
     function(tbl)
         donators = tbl.donators
+        donator_perks_perm = tbl.donator_perks_perm
+        donator_perks_temp = tbl.donator_perks_temp
+        donator_tiers = tbl.donator_tiers
+        config = tbl.global.config.donator.donator_perks
     end
 )
 
 local Public = {}
 
+--- Checks if a player has a specific donator perk
+-- @param player_name <string>
+-- @param perf_flag <number>
+-- @return <boolean>
+function Public.player_has_donator_perk(player_name, perk_flag)
+    local d = donators[player_name]
+    if not d then
+        return false
+    end
+
+    local flags = d.perk_flags
+    if not flags then
+        return false
+    end
+
+    return bit32.band(flags, perk_flag) == perk_flag
+end
+
 --- Prints the donator message with the color returned from the server
 local print_after_timeout =
     Token.register(
@@ -40,6 +75,18 @@ local print_after_timeout =
     end
 )
 
+-- Just in case we want to turn it off mid-game, we can use /sc package.loaded['features.donator'].toggle_perks()
+function Public.toggle_perks()
+    config.donator_perks.enabled = not config.donator_perks.enabled
+    if config.donator_perks.enabled == true then
+        game.print("Donator perks now enabled")
+        print("Donator perks now enabled") -- prints to server console
+    else
+        game.print("Donator perks now disabled")
+        print("Donator perks now disabled")
+    end
+end
+
 --- When a player joins, set a 1s timer to retrieve their color before printing their welcome message
 local function player_joined(event)
     local player = game.get_player(event.player_index)
@@ -52,19 +99,117 @@ local function player_joined(event)
         return nil
     end
 
-    local messages = d.welcome_messages
-    if not messages then
+    local perk_flag = d.perk_flags
+    if perk_flag < 2 then
         return
     end
 
-    local count = #messages
-    if count == 0 then
+    if Public.player_has_donator_perk(player.name, DonatorPerks.welcome_msg) then
+        local messages = d.welcome_messages
+        if messages then
+            local count = #messages
+            if count ~= 0 and count then
+                local message = messages[random(count)]
+                message = concat({'*** ', message, ' ***'})
+                Task.set_timeout_in_ticks(60, print_after_timeout, {player = player, message = message})
+            end
+        end
+    end
+
+    if not config.donator_perks.enabled then
         return
     end
 
-    local message = messages[random(count)]
-    message = concat({'*** ', message, ' ***'})
-    Task.set_timeout_in_ticks(60, print_after_timeout, {player = player, message = message})
+    local mining_flag = Public.player_has_donator_perk(player.name, DonatorPerks.team_mining)
+    local crafting_flag = Public.player_has_donator_perk(player.name, DonatorPerks.team_crafting)
+    local running_flag = Public.player_has_donator_perk(player.name, DonatorPerks.team_run)
+    local inventory_flag = Public.player_has_donator_perk(player.name, DonatorPerks.team_inventory)
+
+    if not mining_flag and not crafting_flag and not running_flag and not inventory_flag then
+        return
+   end
+
+    -- Update team perks
+    if not donator_perks_temp[player.name] then -- check they're not already in donator_perks_temp table, this keeps track of bonuses that are added and removed as players join and leave
+        local donator_perk_msg = concat({"Donator Tier: ",donator_tiers[d.patreon_tier].name, ". Team bonuses applied for ", player.name,": "})
+        if mining_flag and donator_tiers[2].count < donator_tiers[2].max then  -- Apply tier 2 (Coal) reward: +10 % team manual mining bonus per online tier 2+ donator
+            player.force.manual_mining_speed_modifier = player.force.manual_mining_speed_modifier + 0.1
+            donator_tiers[2].count = donator_tiers[2].count + 1
+            donator_perk_msg = concat({donator_perk_msg, "+10% hand mining. "})
+        end
+        if crafting_flag and donator_tiers[3].count < donator_tiers[3].max then  -- Apply tier 3 (Solid Fuel) reward: + 10 % team manual crafting bonus per online tier 3+ donator
+            player.force.manual_crafting_speed_modifier = player.force.manual_crafting_speed_modifier + 0.1
+            donator_tiers[3].count = donator_tiers[3].count + 1
+            donator_perk_msg = concat({donator_perk_msg, "+10% hand crafting. "})
+        end
+        if running_flag and donator_tiers[4].count < donator_tiers[4].max  then  -- Apply Tier 4 (Rocket Fuel) reward: + 10 % team running speed bonus per online tier 4+ donator
+            player.force.character_running_speed_modifier = player.force.character_running_speed_modifier + 0.1
+            donator_tiers[4].count = donator_tiers[4].count + 1
+            donator_perk_msg = concat({donator_perk_msg, "+10% run speed. "})
+        end
+        donator_perks_temp[player.name] = perk_flag
+        if inventory_flag and not donator_perks_perm[player.name] and donator_tiers[5].count < donator_tiers[5].max  then
+            player.force.character_inventory_slots_bonus = player.force.character_inventory_slots_bonus + 5
+            donator_tiers[5].count = donator_tiers[5].count + 1
+            donator_perk_msg = concat({donator_perk_msg, "+5 inventory slots. "})
+            donator_perks_perm[player.name] = true
+        elseif donator_perks_perm[player.name] then -- for if they're already in the table. We don't want to apply the perk again but we do want to append the perk to the message.
+            donator_perk_msg = concat({donator_perk_msg, "+5 inventory slots. "})
+        end
+        donator_perk_msg = donator_perk_msg .. " Use /perks to see bonuses."
+        Task.set_timeout_in_ticks(80, print_after_timeout, {player = player, message = donator_perk_msg})
+    end
+end
+
+local function player_left(event)
+    local player = game.get_player(event.player_index)
+
+    if not player or not player.valid or not config.donator_perks.enabled then
+        return
+    end
+
+    local d = donators[player.name]
+    if not donator_perks_temp[player.name] and not d then
+        return
+    end
+
+    local mining_flag = Public.player_has_donator_perk(player.name, DonatorPerks.team_mining)
+    local crafting_flag = Public.player_has_donator_perk(player.name, DonatorPerks.team_crafting)
+    local running_flag = Public.player_has_donator_perk(player.name, DonatorPerks.team_run)
+
+   -- To do: What happens if an admin changes the players donator status or flags while they're online?
+    if not mining_flag and not crafting_flag and not running_flag then
+        return
+    end
+
+    if donator_perks_temp[player.name] then
+        if mining_flag then
+            if player.force.manual_mining_speed_modifier  >= 0.1 then
+                player.force.manual_mining_speed_modifier = player.force.manual_mining_speed_modifier - 0.1
+            else
+                player.force.manual_mining_speed_modifier =  0
+            end
+            donator_tiers[2].count = donator_tiers[2].count - 1
+        end
+        if crafting_flag then
+            if player.force.manual_crafting_speed_modifier >= 0.1 then
+                player.force.manual_crafting_speed_modifier = player.force.manual_crafting_speed_modifier - 0.1
+            else
+                player.force.manual_crafting_speed_modifier = 0
+            end
+            donator_tiers[3].count = donator_tiers[4].count - 1
+        end
+        if running_flag and player.force.character_running_speed_modifier >= 0.1  then
+            if player.force.character_running_speed_modifier >= 0.1 then
+                player.force.character_running_speed_modifier = player.force.character_running_speed_modifier - 0.1
+            else
+                player.force.character_running_speed_modifier = 0
+            end
+            donator_tiers[4].count = donator_tiers[4].count - 1
+        end
+        donator_perks_temp[player.name] = nil -- remove them from the table
+    end
+
 end
 
 --- Prints a message on donator death
@@ -79,6 +224,9 @@ local function player_died(event)
         return nil
     end
 
+    if not Public.player_has_donator_perk(player.name, DonatorPerks.death_msg) then
+        return
+    end
     local messages = d.death_messages
     if not messages then
         return
@@ -98,12 +246,48 @@ local function player_died(event)
     game.print(message, player.chat_color)
 end
 
+local reset_run_speed =
+    Token.register(
+    function(player)
+        if not player.valid then
+            return
+        end
+        player.character_running_speed_modifier = player.character_running_speed_modifier - 1
+    end
+)
+
+local function player_respawned(event)
+    local player = game.get_player(event.player_index)
+    if not player or not player.valid or not config.donator_perks.enabled then
+        return
+    end
+
+    local d = donators[player.name]
+    if not d then
+        return nil
+    end
+
+    local respawn_flag = Public.player_has_donator_perk(player.name, DonatorPerks.respawn_boost)
+    if not respawn_flag then
+        return
+    end
+
+    player.character_running_speed_modifier = player.character_running_speed_modifier + 1
+    Task.set_timeout_in_ticks(30*60, reset_run_speed, player)
+end
+
 --- Returns the table of donators
 -- @return <table>
 function Public.get_donators_table()
     return donators
 end
 
+--- Returns the table of active perks
+-- @return <table>
+function Public.get_donator_perks_table()
+    return donator_tiers
+end
+
 --- Checks if a player is a donator
 -- @param player_name <string>
 -- @return <boolean>
@@ -111,24 +295,6 @@ function Public.is_donator(player_name)
     return donators[player_name] ~= nil
 end
 
---- Checks if a player has a specific donator perk
--- @param player_name <string>
--- @param perf_flag <number>
--- @return <boolean>
-function Public.player_has_donator_perk(player_name, perk_flag)
-    local d = donators[player_name]
-    if not d then
-        return false
-    end
-
-    local flags = d.perk_flags
-    if not flags then
-        return false
-    end
-
-    return bit32.band(flags, perk_flag) == perk_flag
-end
-
 --- Sets the data for a donator, all existing data for the entry is removed
 -- @param player_name <string>
 -- @param data <table>
@@ -244,6 +410,10 @@ Server.on_data_set_changed(
 
 Event.add(defines.events.on_player_joined_game, player_joined)
 
+Event.add(defines.events.on_player_left_game, player_left)
+
 Event.add(defines.events.on_player_died, player_died)
 
+Event.add(defines.events.on_player_respawned, player_respawned)
+
 return Public
diff --git a/features/donator_commands.lua b/features/donator_commands.lua
index 8f6273ee..75fa23b8 100644
--- a/features/donator_commands.lua
+++ b/features/donator_commands.lua
@@ -3,8 +3,20 @@ local Game = require 'utils.game'
 local Command = require 'utils.command'
 local Donator = require 'features.donator'
 local Color = require 'resources.color_presets'
+local Global = require 'utils.global'
 
 local format = string.format
+local config = global.config.donator.donator_perks
+
+
+Global.register(
+    {
+        config = config
+    },
+    function(tbl)
+        config = tbl.global.config.donator.donator_perks
+    end
+)
 
 -- Local functions
 
@@ -73,6 +85,26 @@ local function donator_death_message_command(args, player)
     command_path_decider(args, player, table_name)
 end
 
+-- Prints a list of currently active perks to the player
+local function print_perks(_, player)
+    local print = print
+    if player and player.valid then -- allows us to call print_perks from the server console OR in-game
+        print = player.print
+    end
+
+    if not config.enabled then
+        print("Donator perks have been disabled for this map.")
+        return
+    end
+
+    local donator_tiers = Donator.get_donator_perks_table()
+
+    print("Currently active team perks: +"..(donator_tiers[2].count*10).."% hand mining speed (max +"..(donator_tiers[2].max*10).."%), +"
+        ..(donator_tiers[3].count*10).."% hand crafting speed (max +"..(donator_tiers[3].max*10).."%), +"
+        ..(donator_tiers[4].count*10).."% run speed  (max +"..(donator_tiers[4].max*10).."%) and +"
+        ..(donator_tiers[5].count*5).." inventory slots  (max +"..(donator_tiers[5].max*5).."%).")
+end
+
 -- Commands
 
 Command.add(
@@ -98,3 +130,11 @@ Command.add(
     },
     donator_death_message_command
 )
+
+Command.add(
+    'perks',
+    {
+        description = {'command_description.perks'},
+    },
+    print_perks
+)
\ No newline at end of file
diff --git a/locale/en/redmew_command_text.cfg b/locale/en/redmew_command_text.cfg
index 371754ce..5cd1ed0f 100644
--- a/locale/en/redmew_command_text.cfg
+++ b/locale/en/redmew_command_text.cfg
@@ -14,7 +14,6 @@ crash_site_spy=Spend coins to send a fish to spy on the enemy for a short time.
 crash_site_spy_invalid=You need to add a valid location to send a spy fish. e.g /spy [gps=-110,-17,redmew]
 crash_site_spy_funds=Training these spy fish ain't cheap! You need more coins!
 crash_site_spy_success=__1__ used the /spy command and spent __2__ coins to train a fish to spy on the enemy [gps=__3__,__4__,redmew]
-
 crash_site_airstrike_invalid=Invalid co-ordinates.
 crash_site_airstrike=Launch an airstrike against the enemy with poison capsules.
 crash_site_airstrike_count=Upgrade the airstrike damage to  to level __1__\n\nTo use airstrike place poison capsules in the spawn chest then type /strike followed by a gps position\n\nDamage upgrades increase the number of poison capsules launched by airstrike.\n\nCurrent level: __2__\nCurrent shell count: __3__\nCurrent cost: __4__
@@ -108,6 +107,7 @@ quick_bar_load=Loads your quick bars from the server (overwriting existing bars)
 quick_bar_delete=Erases your saved quick bars from the server
 set_pollution_multiplier=EXPERIMENTAL. An integer which gets multiplied by 0.01 to give the amount of pollution crash site magic crafters emit. Default is 0
 get_pollution_multiplier=The current pollution multiplier for crash site. The default is 0.
+perks=Lists Patreon donators that are contributing to currently active perks.
 
 [command_custom_help]
 tp=<blank|mode|player> 3 different uses: "/tp" to tp to selected entity. "/tp mode" to toggle tp mode. "/tp Newcott" to tp to Newcott.
diff --git a/resources/donator_perks.lua b/resources/donator_perks.lua
index 1e68bc6d..70331b3e 100644
--- a/resources/donator_perks.lua
+++ b/resources/donator_perks.lua
@@ -1,4 +1,18 @@
 return {
-    rank = 0x1,
-    train = 0x2
+    rank = 0x1,                 -- T1
+    train = 0x2,                -- T3. train saviour perk
+    welcome_msg = 0x4,          -- T2. enables a message upon player join
+    team_mining = 0x8,          -- T2. boosts team manual mining speed while player is online
+    death_msg = 0x10,           -- T3. enables a message upon player death
+    team_crafting = 0x20,       -- T3. boosts team manual crafting speed while player is online
+    team_run = 0x40,            -- T4. boosts team run speed while player is online
+    respawn_boost = 0x80,      -- T4. player runs faster for 30 seconds after respawn
+    team_inventory = 0x160      -- T5. boosts team inventory size for remainder of map
 }
+
+-- 2021-12-30
+-- Tier 1 = 1
+-- Tier 2 = 8 + 4 + 1 = 21
+-- Tier 3 = 8 + 4 + 1 + 16 + 32 + 2=  63
+-- Tier 4 = 63 + 64 + 128 = 255
+-- Tier 5 = 255 + 256 = 511
\ No newline at end of file