[GAME MODE] Push

15 posts Page 1 of 1
danhezee
Former Admin / Co-founder
Former Admin / Co-founder
Posts: 1709
Joined: Wed Oct 03, 2012 12:09 am


Push is a very exciting intense gamemode where teams bridge their way across chains of islands to cap the intel all the while keeping a close on the enemy attempting to do the same thing.

Push is driven by map extensions. The map makers set spawn size, spawn locations, and command post locations for each team and sets water damage to 100. Use the code below as a guide to create your own push maps.
Code: Select all
extensions = {
'push': True,
'push_spawn_range' : 5,
'push_blue_spawn' : (91, 276, 59),
'push_blue_cp' : (91, 276, 59),
'push_green_spawn' : (78, 86, 59),
'push_green_cp' : (78, 86, 59),
'water_damage' : 100
  }
This script itself:
Code: Select all
# The idea of Push
# 	Teams spawn at set locations with the intel
#	They push the intel towards the CP's, which is also a set location
#
#Essentially we need read the map meta data get the spawn and cp locations 
#	and have the players and cp spawn at the apporiate locations
#
#Bonus feature: on intel cap the map rollbacks
#
# Sample extensions dictionary of an arena map with two gates:
# In this example there is one spawn location for blue and two spawn locations for green.
# extensions = {
#      'push': True,
#	   'push_spawn_range' : 5,
#      'push_blue_spawn' : (91, 276, 59),
#	   'push_blue_cp' : (91, 276, 59),
#      'push_green_spawn' : (78, 86, 59),
#	   'push_green_cp' : (78, 86, 59),
#      'water_damage' : 100
 # }
from pyspades.constants import *
from random import randint
from commands import add, admin
from twisted.internet.task import LoopingCall
from pyspades.constants import CTF_MODE

# If ALWAYS_ENABLED is False, then the 'push' key must be set to True in
# the 'extensions' dictionary in the map metadata
ALWAYS_ENABLED = False

GRIEF_PROTECTION = False
KILL_REQUIREMENT = 5

#team is associated intel team
def reset_intel(protocol, team):
	extensions = protocol.map_info.extensions

	if team is protocol.green_team and extensions.has_key('push_blue_spawn'):
		z = protocol.map.get_z(*extensions.get('push_blue_spawn'))
		pos = (extensions.get('push_blue_spawn')[0], extensions.get('push_blue_spawn')[1], z)

	if team is protocol.blue_team and extensions.has_key('push_green_spawn'):
		z = protocol.map.get_z(*extensions.get('push_green_spawn'))
		pos = (extensions.get('push_green_spawn')[0], extensions.get('push_green_spawn')[1], z)

	team.flag.set(*pos)
	team.flag.update()
	protocol.send_chat("The %s intel has been reset." % team.name)

@admin
def resetblueintel(connection):
	reset_intel(connection.protocol, connection.protocol.blue_team)

@admin
def resetgreenintel(connection):
	reset_intel(connection.protocol, connection.protocol.green_team)

add(resetblueintel)
add(resetgreenintel)

def get_entity_location(self, entity_id):
	extensions = self.protocol.map_info.extensions

	if entity_id == BLUE_BASE and extensions.has_key('push_blue_cp'):
		return extensions['push_blue_cp']
	elif entity_id == GREEN_BASE and extensions.has_key('push_green_cp'):
		return extensions['push_green_cp']
	#this next part might seem counter intiutive but you need the blue intel to spawn near the greens and vice versa
	elif entity_id == BLUE_FLAG and extensions.has_key('push_green_spawn'):
		return extensions['push_green_spawn']
	elif entity_id == GREEN_FLAG and extensions.has_key('push_blue_spawn'):
		return extensions['push_blue_spawn']
	
def get_spawn_location(connection):
	extensions = connection.protocol.map_info.extensions
	#distance from spawn center to randomly spawn in
	spawn_range = 5;
	if extensions.has_key('push_spawn_range'):
		spawn_range = extensions['push_spawn_range']
		
	if connection.team is connection.protocol.blue_team:
		if extensions.has_key('push_blue_spawn'):
			xb = extensions.get('push_blue_spawn')[0]
			yb = extensions.get('push_blue_spawn')[1]
			xb += randint(-spawn_range, spawn_range)
			yb += randint(-spawn_range, spawn_range)
			return (xb, yb, connection.protocol.map.get_z(xb, yb))
	
	if connection.team is connection.protocol.green_team:
		if extensions.has_key('push_green_spawn'):
			xb = extensions.get('push_green_spawn')[0]
			yb = extensions.get('push_green_spawn')[1]
			xb += randint(-spawn_range, spawn_range)
			yb += randint(-spawn_range, spawn_range)
			return (xb, yb, connection.protocol.map.get_z(xb, yb))

def apply_script(protocol, connection, config):

	class PushProtocol(protocol):
		push = False
		check_loop = None
		game_mode = CTF_MODE

		def check_intel_locations(self):
			if self.blue_team.flag is not None:
				if self.blue_team.flag.get()[2] >= 63:
					reset_intel(self, self.blue_team)
			if self.green_team.flag is not None:
				if self.green_team.flag.get()[2] >= 63:
					reset_intel(self, self.green_team)

		def on_map_change(self, map):
			extensions = self.map_info.extensions

			if ALWAYS_ENABLED:
				self.push = True
			else:
				if extensions.has_key('push'):
					self.push = extensions['push']
				else:
					self.push = False
			if self.push:
				self.map_info.get_entity_location = get_entity_location
				self.map_info.get_spawn_location = get_spawn_location
				self.check_loop = LoopingCall(self.check_intel_locations)
				self.check_loop.start(0.5)

			return protocol.on_map_change(self, map)

	# class PushConnection(connection):
		
		# kill_reputation = 0

		# def on_team_changed(self, old_team):
			# self.kill_reputation = 0
			# return connection.on_team_changed(self, old_team)

		# def on_block_destroy(self, x, y, z, mode):
			# if GRIEF_PROTECTION and self.kill_reputation < KILL_REQUIREMENT:
				# self.send_chat("You need more kills to be able to destroy blocks.")
				# return False
			# return connection.on_block_destroy(self, x, y, z, mode)

		# def on_kill(self, killer, type, grenade):
			# self.kill_reputation += 1
			# return connection.on_kill(self, killer, type, grenade)

	return PushProtocol, connection		
MKU
Artist
Artist
Posts: 383
Joined: Wed Oct 31, 2012 12:20 am


You stole this idea from Jdrew.
izzy
Head Admin / Co-founder
Head Admin / Co-founder
Posts: 473
Joined: Tue Oct 09, 2012 8:16 pm


Simple concept and yet so fun.

aloha.pk push server:

Join: [aos]aos://1379434439:49887[/aos]
Status: http://west.aloha.pk:49886/
izzy
Head Admin / Co-founder
Head Admin / Co-founder
Posts: 473
Joined: Tue Oct 09, 2012 8:16 pm


Danke and I added anti grief measures. Now each team is forced to place blocks in random shades of their team's color:

Image
  • Blue team cannot destroy blue blocks.
  • Blue team can destroy green blocks.
  • Green team cannot destroy green blocks.
  • Green team can destroy blue blocks.
  • A player can remove his own last 5 placed blocks.
  • A player logged in as trusted, guard, moderator, or admin can remove all blocks placed by anyone.
Here's the updated script:
Code: Select all
"""
push.py last modified 2013-02-25 10:52:53
Contributors: danhezee, StackOverflow, izzy, Danke

The concept:
    Each team spawns at a set location with the enemy intel.
    They must "push" the intel towards their control point, which is also at a set location.

How to setup new maps:
    Spawn and CP locations must be configured via extensions in the map's map_name.txt metadata. Example:

extensions = {
    'push': True,
    'push_spawn_range' : 5,
    'push_blue_spawn' : (91, 276, 59),
    'push_blue_cp' : (91, 276, 59),
    'push_green_spawn' : (78, 86, 59),
    'push_green_cp' : (78, 86, 59),
    'water_damage' : 100
}
"""

from pyspades.constants import *
from random import randint
from commands import add, admin
from twisted.internet.task import LoopingCall
from pyspades.common import make_color
from pyspades.server import set_color, block_action
import random

# If ALWAYS_ENABLED is False, then the 'push' key must be set to True in
# the 'extensions' dictionary in the map's map_name.txt metadata
ALWAYS_ENABLED = True

#team is associated intel team
def reset_intel(protocol, team):
    extensions = protocol.map_info.extensions

    if team is protocol.green_team and extensions.has_key('push_blue_spawn'):
        z = protocol.map.get_z(*extensions.get('push_blue_spawn'))
        pos = (extensions.get('push_blue_spawn')[0], extensions.get('push_blue_spawn')[1], z)

    if team is protocol.blue_team and extensions.has_key('push_green_spawn'):
        z = protocol.map.get_z(*extensions.get('push_green_spawn'))
        pos = (extensions.get('push_green_spawn')[0], extensions.get('push_green_spawn')[1], z)

    team.flag.set(*pos)
    team.flag.update()
    protocol.send_chat("The %s intel has been reset." % team.name)

@admin
def resetblueintel(connection):
	reset_intel(connection.protocol, connection.protocol.blue_team)

@admin
def resetgreenintel(connection):
    reset_intel(connection.protocol, connection.protocol.green_team)

add(resetblueintel)
add(resetgreenintel)

def get_entity_location(self, entity_id):
    extensions = self.protocol.map_info.extensions

    if entity_id == BLUE_BASE and extensions.has_key('push_blue_cp'):
        return extensions['push_blue_cp']
    elif entity_id == GREEN_BASE and extensions.has_key('push_green_cp'):
        return extensions['push_green_cp']
    #this next part might seem counter intuitive but you need the blue intel to spawn near the greens and vice versa
    elif entity_id == BLUE_FLAG and extensions.has_key('push_green_spawn'):
        return extensions['push_green_spawn']
    elif entity_id == GREEN_FLAG and extensions.has_key('push_blue_spawn'):
        return extensions['push_blue_spawn']
	
def get_spawn_location(connection):
    extensions = connection.protocol.map_info.extensions
    #distance from spawn center to randomly spawn in
    spawn_range = 5;
    if extensions.has_key('push_spawn_range'):
        spawn_range = extensions['push_spawn_range']
		
    if connection.team is connection.protocol.blue_team:
        if extensions.has_key('push_blue_spawn'):
            xb = extensions.get('push_blue_spawn')[0]
            yb = extensions.get('push_blue_spawn')[1]
            xb += randint(-spawn_range, spawn_range)
            yb += randint(-spawn_range, spawn_range)
            return (xb, yb, connection.protocol.map.get_z(xb, yb))
	
    if connection.team is connection.protocol.green_team:
        if extensions.has_key('push_green_spawn'):
            xb = extensions.get('push_green_spawn')[0]
            yb = extensions.get('push_green_spawn')[1]
            xb += randint(-spawn_range, spawn_range)
            yb += randint(-spawn_range, spawn_range)
            return (xb, yb, connection.protocol.map.get_z(xb, yb))

def apply_script(protocol, connection, config):
    class PushConnection(connection):
        def on_login(self, name):
            self.mylastblocks = [(-4,-1,-14),(-11,-5,-9),(-19,-20,-8),(-5,-2,-5),(-19,-20,0)]
            return connection.on_login(self, name)
        def random_color(self):
            color = (0, random.randint(min(32,self.team.color[1]), max(self.team.color[1],32))*self.team.color[1]/255,
                        random.randint(min(32,self.team.color[2]), max(self.team.color[2],32))*self.team.color[2]/255 )
            self.color = color
            set_color.player_id = self.player_id
            set_color.value = make_color(*color)
            self.send_contained(set_color)
            self.protocol.send_contained(set_color, save = True)

        def build_block(self,x,y,z,looped = False):
            if (x < 0 or x > 511 or y < 0 or y > 511 or z < 1 or z > 61) is False:
                self.protocol.map.set_point(x, y, z, self.color)
                block_action.x = x
                block_action.y = y
                block_action.z = z
                block_action.value = BUILD_BLOCK
                block_action.player_id = self.player_id
                self.protocol.send_contained(block_action, save = True)

        def on_line_build_attempt(self, points):
            if connection.on_line_build_attempt(self, points) is not False:
                for point in points:
                    x,y,z = point[0], point[1], point[2]
                    self.mylastblocks.pop(0)
                    self.mylastblocks.append((x,y,z))
                    self.random_color()
                    self.build_block(x,y,z)
            return False

        def on_block_build_attempt(self, x, y, z):
            if connection.on_block_build_attempt(self, x, y, z) is not False:
                self.mylastblocks.pop(0)
                self.mylastblocks.append((x,y,z))
                self.random_color()
                self.build_block(x,y,z)
            return False

        def on_block_destroy(self, x, y, z, value):
            if not (self.admin or self.user_types.moderator or self.user_types.guard or self.user_types.trusted):
                if value == DESTROY_BLOCK:
                    blocks = ((x, y, z),)
                elif value == SPADE_DESTROY:
                    blocks = ((x, y, z), (x, y, z + 1), (x, y, z - 1))
                elif value == GRENADE_DESTROY:
                    blocks = []
                    for nade_x in xrange(x - 1, x + 2):
                        for nade_y in xrange(y - 1, y + 2):
                            for nade_z in xrange(z - 1, z + 2):
                                blocks.append((nade_x, nade_y, nade_z))
                for block in blocks:
                    for lastblock in self.mylastblocks:
                        if lastblock == block:
                            self.mylastblocks.remove(lastblock)
                            self.mylastblocks.append((-1,-1,-1))
                            return connection.on_block_destroy(self, x, y, z, value)
                    block_info = self.protocol.map.get_point(block[0], block[1], block[2])
                    if block_info[0] == True and self.team is self.protocol.blue_team:
                            if block_info[1][0] == 0 and block_info[1][1] == 0 and block_info[1][2] > 0:
                                self.send_chat("You can't destroy your team's blocks. Attack the enemy!")
                                return False
                    elif block_info[0] == True and self.team is self.protocol.green_team:
                            if block_info[1][0] == 0 and block_info[1][1] > 0 and block_info[1][2] == 0:
                                self.send_chat("You can't destroy your team's blocks. Attack the enemy!")
                                return False
            return connection.on_block_destroy(self, x, y, z, value)

    class PushProtocol(protocol):
        game_mode = CTF_MODE
        push = False
        check_loop = None

        def check_intel_locations(self):
            if self.blue_team.flag is not None:
                if self.blue_team.flag.get()[2] >= 63:
                    reset_intel(self, self.blue_team)
            if self.green_team.flag is not None:
                if self.green_team.flag.get()[2] >= 63:
                    reset_intel(self, self.green_team)

        def on_map_change(self, map):
            extensions = self.map_info.extensions
            if ALWAYS_ENABLED:
                self.push = True
            else:
                if extensions.has_key('push'):
                    self.push = extensions['push']
                else:
                    self.push = False
            if self.push:
                self.map_info.get_entity_location = get_entity_location
                self.map_info.get_spawn_location = get_spawn_location
                self.check_loop = LoopingCall(self.check_intel_locations)
                self.check_loop.start(0.5)
            return protocol.on_map_change(self, map)

    return PushProtocol, PushConnection
Handles
League Participant
League Participant
Posts: 1087
Joined: Tue Jan 08, 2013 9:46 pm


Looks good!
Cajun Style
Deuced Up
Posts: 145
Joined: Fri Dec 07, 2012 11:04 am


Both scripts ignore the z-coordinate for player spawns. Could that be fixed, or is it necessary to respect the map height?
Handles
League Participant
League Participant
Posts: 1087
Joined: Tue Jan 08, 2013 9:46 pm


I think it can be fixed. Oh and Dan can you script my next map when im finished? Green_BigSmile
noway
Deuced Up
Posts: 22
Joined: Wed Dec 12, 2012 10:28 am


Game mode works only with default team colors (blue and green).
All breaks if set some custom.

I fix this. Also, some code style improvements.

http://pastebin.com/qMNEFqeS
thepolm3
Scripter
Scripter
Posts: 424
Joined: Sat Feb 16, 2013 10:49 pm


Nice :) do you know how to write pyspades scripts?
noway
Deuced Up
Posts: 22
Joined: Wed Dec 12, 2012 10:28 am


Very little. I'm not completely understand pyspades api.
thepolm3
Scripter
Scripter
Posts: 424
Joined: Sat Feb 16, 2013 10:49 pm


do you want some help?
Venator
League Participant
League Participant
Posts: 1225
Joined: Wed Nov 07, 2012 8:32 pm


10/10 would play if there wouldnt only be playing deathmatching lil kids.
noway
Deuced Up
Posts: 22
Joined: Wed Dec 12, 2012 10:28 am


New version. Fixed bug when player can destroy own team blocks with grenade.
Check for intel in water moved to on_flag_drop.
Fixed some small bugs. And some other improvements.
http://pastebin.com/VtyQiMxB
IAmYourFriend
Global Moderator
Global Moderator
Posts: 102
Joined: Fri Nov 16, 2012 8:58 pm


Based on the last version posted by noway in this thread, i made the following changes:

Bugfixes:
  • Fixed the bug where the intel was sometimes not reset after it was dropped in the water.
New anti-grief measures:
  • The intel will be reset every 5 minutes, after it was dropped somewhere. This is to handle the case when people drop the intel at places where it is almost impossible to pick it up again (on the enemy side for example), or if people cover the intel with blocks.
  • It is not possible to build at your own teams tent in an 8 block radius. This is to prevent griefers covering the tent in blocks so no one could capture the intel anymore.
  • Added additional, but only optional, map extension parameters for the txt file (so this push script version will still work fine with map txt files that don't have the new parameters). The purpose here is to define a build area for each team, and then to disallow a team building bridges for the enemy team. This has happened alot in push games, be it intentional griefing or just by players who have no clue - usually once one team reaches its tent, some people start building on the enemy side towards the enemy team, therefore completing their bridges (those bridges on your enemies side can't even be destroyed then anymore as they have been built by your own team).
    The new parameters are push_blue_build_area and push_green_build_area and consist of four values (x and y of upper left corner, x and y of bottom right corner) to mark a rectangle on the map where a team is building their bridges.
I have made these changes several month ago for the *Sauerkraut push server, so this version has already been playtested many times.
Since finding the right values for the new txt parameters is not always easy, here a zip with updated map txt files for 8 push maps that include the right build area values: http://www.mediafire.com/download/ohtjo ... apstxt.zip
Attachments
push.py
(14.57 KiB) Downloaded 165 times
IAmYourFriend
Global Moderator
Global Moderator
Posts: 102
Joined: Fri Nov 16, 2012 8:58 pm


The version i posted here before seems to have a bug when using OpenSpades, placing 1 block results in 2 block being removed from blockcount there. The function "build_block" adds the placed block to the map, while it is also added anyway in the usual manner, so a quick fix would be to comment out (or remove) lines 224 and and 243.
I guess the function could be removed, not sure what it's original purpose/idea was, i might post an update with a bit of a cleanup some time later.
15 posts Page 1 of 1
Return to “Game Modes”

Who is online

Users browsing this forum: No registered users and 1 guest