MIRACULAR

The Miracular is the most powerful ancient artifact known to mankind. He who holds it, becomes invisible. Simple as that. No one knows how it works, but if it falls into the wrong hands, empires will collapse.

MIRACULAR is a 2D (Bird's Eye View) browser-based MMORPG with a fantasy steampunk theme + ancient artifacts that give viability for the use of magic. This game does not simply revolve around combat like so many others out there. This game is about stealth. The ability of not being seen or heard is prized above the ability to kill. the goal is not to kill everyone, instead it is to steal intelligence and money. Killing is just an approach, a dangerous one at that, to achieve all of the intelligence and money you need.


Main Goals:
A game that focuses less on combat, and more on stealth.
Cooperative gameplay.
Read on.


Mechanics:
Two modes: Regular and stealth.

Upon entering stealth mode, enemies around you have a color coded cone of vision (approx 70-90 degrees) and a similar colored circle of hearing. The shapes are very transparent but project enough color to be visible so that you don't randomly wander into one. The color coding represents detection, green is not suspicious at all and it turns redder as suspicion increases or you are found out. Suspicious enemies have a higher priority over not suspicious enemies thus if their cones overlap, the suspicious one's displays above the not suspicious one's. Avoiding both of these can get you by any enemy. The skills, below, affect the stealth mode and the length/radius of the detection shapes. The mode also highlights pieces of intel.

Collecting this intel will benefit you. The intel is used to find money, items or lead you to contracts.

It is very difficult to kill people outright so you have to assassinate them or avoid combat as much as possible. If you are ever found out, an alarm is triggered in search for you. You try to get away before they capture you. If they capture you, you lose some money and get teleported to a safe area.


Possible Skills:
All of the skills are numbers from 1-100.

Intel: No inherent effect. Raises as you find pieces of intelligence AND use them.

Stealth: Decreases the chance that an enemy will visually detect you.

Muffle: Decreases the chance that an enemy will detect you by sound.

Assassination: Dampens the noise created when assassinating someone, therefore lowers your chance of being detected by near enemies when performing the action.

Lockpicking: Increases the chance of successfully picking a lock and allows you to pick higher level locks.

Pickpocketing: Increases the chance of successfully stealing items from someones pockets without them noticing.

Hacking: Increases the chance of hacking into magical turrets/sensors and disabling them or even turning them to your side.

Gadget: Allows you to create gadgets (sensors, traps etc.)

Disguise: Increases effectiveness of a disguise, allowing you to blend in to a group of people or impersonate a person you recently killed (you have to get the disguise somewhere.)

Persuasion: Better chance of persuading people to do stuff for you or alter their actions.

Distraction: Increases chance of using a distraction to lure enemies away from your position (throwing your voice, throwing a pebble, etc)

These are it so far, tell me if you want to add more or change the structure of some of them.


Please go to: https://trello.com/b/DlC8eKed for more information on where I am in the making of said game.


Game Website: Under Construction.


Some Information About Game Developement:
Pre-alpha: Basically means that most of the core mechanics and content has not been added. People I know in real life get to participate in this phase.

Alpha: Most of the core mechanics and a core content has been added. For me, this means that I have all of the communication between the server and the clients, an account database, and the skeleton for most of the other mechanics set up. People I know in real life, along with active forum users on here can register.

Beta: All of the core and extra mechanics set up. Most of the core and extra content also added. Later beta phase is testing and bug fixing. Early beta: same as alpha registration. Later beta: Open registration on the game website.


Currently at: Pre-Alpha V 1.0
Basically a chat box on the client that communicates with the game server allowing for multiple people to talk to each other.


Working towards: Pre-Alpha V 1.1
A room in which colored boxes representing players can move around. No interaction yet. The previously mentioned chat box will be on the bottom of the screen with the main area dedicated to the game itself. This lays the foundation for the communication between the server and the clients.


Updates:
Successfully figured out how to send and receive packets of data and distinguishing where they came from. Working on the basic chat server now.

Updating this page and the idea itself. Working on the basic server and client. Testing bytebuffers and channels in java. http://tutorials.jenkov.com/java-nio/index.html
Since you imagine it as massively-multiplayer but in Java, what will you be writing the server-side component of the software in? Do you already have a virtual or dedicated server where you'll be running the coordination software?
KermMartian wrote:
Since you imagine it as massively-multiplayer but in Java, what will you be writing the server-side component of the software in? Do you already have a virtual or dedicated server where you'll be running the coordination software?


I think he told me last night he would be writing that in Java too Smile And he indeed has a decent server, which I myself use for SVN storage. He actually knows how to work with server-client side connections rather well, as he proved from out last contest (he programmed most if not all of the networking code) so I think he'd be able to tackle it, which I'm sure may be your next question, Kerm Wink thing is, I'm trying to give him ideas on what type of game in general to make; He knows he wants it multiplayer, but he's split between making an RPG, a Tower Defense game, or something else -- a rather big conceptual split if I do say so myself.
I decided on an RPG style game. I'm updating the main post and trello to make then both look more professional, having an ideas, goals, updates, etc. sections.

KermMartian wrote:
Since you imagine it as massively-multiplayer but in Java, what will you be writing the server-side component of the software in? Do you already have a virtual or dedicated server where you'll be running the coordination software?


The server-side component will be written in java as I know it the best and I have the previous experience from the IDT competition. As Ashbad mentioned, I do have a server that I'll be running it on. And nice to meet you Kerm.
I noticed on skype today before our "jam session" that you were playing other MMORPG games like Runescape to get a feel for what type of mechanics are popular amongst games of this genre; any updates in specific game design as a result of this fun little field study? Smile

And might I inquire, if you need someone to help you with spriting once placeholder graphics are removed, or if you need some help, just tell me and I'll pull it from your SVN server and start helping pronto.

EDIT: I also noticed from your trello that you plan on making the weapons "TF2 style", with pros and cons for each item, instead of the traditional approach where items follow a chain of getting stronger the more expensive they become, and the higher the skill level required to use them. Any ideas on what types of perks might be seen from these?
Ashbad wrote:
I noticed on skype today before our "jam session" that you were playing other MMORPG games like Runescape to get a feel for what type of mechanics are popular amongst games of this genre; any updates in specific game design as a result of this fun little field study? Smile

And might I inquire, if you need someone to help you with spriting once placeholder graphics are removed, or if you need some help, just tell me and I'll pull it from your SVN server and start helping pronto.

EDIT: I also noticed from your trello that you plan on making the weapons "TF2 style", with pros and cons for each item, instead of the traditional approach where items follow a chain of getting stronger the more expensive they become, and the higher the skill level required to use them. Any ideas on what types of perks might be seen from these?


I'm updating my main post now with the information you asked for.
I do indeed like the new stats and mechanics, building upon what we discussed yesterday at the FIRST meeting. I think the different new skills that you decided on are rather creative; the one thing I'm not sure I like is the color-coded cones thing, unless you mean that is shows on a mini-map or radar. Otherwise it would sound graphically annoying.
I should probably clarify. It will be very transparent on the screen, invisible on the minimap, the point is for it to be very transparent red where enemies can see but visible enough so you dont wander into it unknowingly. The stealth mode toggles that and the point of stealth is not to get detected so it should help. Finding a balance between annoying and invisible is key.
zzCorrode wrote:
I should probably clarify. It will be very transparent on the screen, invisible on the minimap, the point is for it to be very transparent red where enemies can see but visible enough so you dont wander into it unknowingly. The stealth mode toggles that and the point of stealth is not to get detected so it should help. Finding a balance between annoying and invisible is key.


Ah, fair deal Smile I was thinking it would be obnoxious like in "The Classroom", where it's like 50% translucent. It sounds like it'll be a lot more subtle, which seems better to me. Good luck!
Quote:
And he indeed has a decent server, which I myself use for SVN storage. He actually knows how to work with server-client side connections rather well, as he proved from out last contest (he programmed most if not all of the networking code) so I think he'd be able to tackle it, which I'm sure may be your next question, Kerm Wink
Well, that's a refreshing change, especially from a Java coder. Wink I'm enjoying keeping an eye on your on-going dialog about this; don't let my silence imply it's boring.
Well that's good news. The latest update to the top post made the entire game a lot more interesting. So far, the people I've talked to about it have replied very positively to my ideas. The networking is a lot harder than I anticipated though.

Edit: I've been working with the TCP side for both the client and server. The TCP connection, for those of you who don't know, is a maintained internet connection between two ip addresses and ports. This guarantees packets being sent and received. This is good for things like chat, damage outputs, or other things that have to be received and don't happen often enough or are too unique for the connection to drop some of that information. I'm almost done with a test TCP server and client which will allow me to translate it to the real game and implement the chat function. Run-on sentences FTW.
If anyone knows the java.nio package well, I'd appreciate the help. I haven't had the time to work on it lately but I have been developing the idea. More updates coming soon.
MAJOR UPDATE

Major for me at least. A server-to-multiple-client chat function has been implemented. At the current moment it works like so: Clients connect to the server via a TCP SocketChannel. A user types in their username and the server stores it in a hashmap. Then, whenever any client sends a message, the server distributes that message among the rest of the clients that are connected. I'm implementing small things like a notification to all clients when a user connects and a more optimized system of distributing messages. I'll put up source code once I clean it up and implement small features that most mmos have. More updates coming soon. Interestingly enough, I worked on it a little bit between writing this and have implemented half of the more optimized distribution of messages.

Stay tuned for more updates.
Nice work Smile I saw it progressing earlier today, to the point it was basically like a simple custom version of the IRC protocol. Any progress on the UDP clients/servers?
None at the moment, I'm just setting up the TCP side now. UDP comes next.
Another huge update. Here is the source code to a working TCP client and server.

Server:

Code:
package tcptest;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;

public class TCPServer {

    private String address;
    private int port;
    private Selector selector;
    private Map<SocketChannel, List<byte[]>> dataMap;
    private Map<SocketChannel, String> userNameMap;

    public TCPServer(String address, int port) throws IOException {
        this.address = address;
        this.port = port;
        dataMap = new HashMap<>();
        userNameMap = new HashMap<>();
        setupServer();
        startServer();
    }

    private void setupServer() throws IOException {
        this.selector = Selector.open();
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);

        InetSocketAddress listenAddress = new InetSocketAddress(address, port);
        serverChannel.socket().bind(listenAddress);
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        log("Server Ready. Press ctrl-c to exit");

    }

    private void startServer() {
       while (true) {
            try {
                runServer();
            } catch (IOException ex) {
                err("Server failed. Shutting down...");
                return;
            }
        }
    }

    private void runServer() throws IOException {
        this.selector.select();

        Iterator keys = this.selector.selectedKeys().iterator();
        while (keys.hasNext()) {
            SelectionKey key = (SelectionKey) keys.next();

            keys.remove();

            if (!key.isValid()) {
                continue;
            }

            if (key.isAcceptable()) {
                this.accept(key);
            } else if (key.isReadable()) {
                this.read(key);
            } else if (key.isWritable()) {
                this.write(key);
            }
        }
    }

    private void accept(SelectionKey key) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
        SocketChannel channel = serverChannel.accept();
        channel.configureBlocking(false);

        Socket socket = channel.socket();
        SocketAddress remoteAddr = socket.getRemoteSocketAddress();
        log("Connected to: " + remoteAddr);

        dataMap.put(channel, new ArrayList<byte[]>());
        userNameMap.put(channel, null);
        channel.register(this.selector, channel.validOps());
    }

    private void read(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();

        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int numRead = -1;
        try {
            numRead = channel.read(buffer);
        } catch (IOException e) {
            err("Failed to read from: " + channel.getRemoteAddress());
        }

        if (numRead == -1) {
            this.dataMap.remove(channel);
           
            log("Connection closed by " + userNameMap.get(channel) + ": " + channel.getRemoteAddress());
            if (userNameMap.get(channel) != null) {
                writeToAllClients(channel, userNameMap.get(channel)+ "(" + channel.getRemoteAddress() + ") "+ " left the game.");
            } else {
                writeToAllClients(channel, "Guest(" + channel.getRemoteAddress() + ") left the game.");
            }
            channel.close();
            key.cancel();
            return;
        }

        byte[] data = new byte[numRead];
        System.arraycopy(buffer.array(), 0, data, 0, numRead);
        String s = new String(data, "US-ASCII");
        if (s.indexOf("text: ") == 0) {
            writeToAllClients(channel, log(userNameMap.get(channel) + ": " + s.substring("text: ".length())));
        } else if (s.indexOf("user: ") == 0) {
            String t = s.substring("user: ".length());
            userNameMap.put(channel, t);
            writeToAllClients(channel, log(t + " joined the game"));
        }
    }

    public void writeToAllClients(SocketChannel channel, String t) {
        for(SocketChannel sc : dataMap.keySet()) {
            if(!sc.equals(channel)) {
                dataMap.get(sc).add(t.getBytes());
            }
        }
    }

    private void write(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        List<byte[]> pendingData = this.dataMap.get(channel);
        if (pendingData.isEmpty()) {
            return;
        }
        Iterator<byte[]> items = pendingData.iterator();
        while (items.hasNext()) {
            byte[] item = items.next();
            items.remove();
            channel.write(ByteBuffer.wrap(item));
        }
    }

    private String log(String s) {
        System.out.println(s);
        return s;
    }

    private String err(String s) {
        System.err.println(s);
        return s;
    }
   
    public static void main(String[] args) throws IOException {
        TCPServer server = new TCPServer("127.0.0.1", 10000);
    }
}


Client:

Code:
package tcptest;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;

public class TCPClient implements Runnable {

    private Thread thread;
    private InetSocketAddress address;
    private Selector selector;
    private SocketChannel channel;
    private ArrayList<byte[]> pendingData;

    public TCPClient(InetSocketAddress address) throws IOException {
        this.address = address;
        pendingData = new ArrayList<>();
        setupSocket();
        start();
    }

    private void setupSocket() throws IOException {
        selector = Selector.open();
        channel = SocketChannel.open();
        channel.socket().connect(address);
        channel.configureBlocking(false);
        channel.register(selector, channel.validOps());
        log("Socket set up. Connected to: " + channel.getRemoteAddress());
        log("Client Loaded. Press ctrl-c to exit.");
        log("Type in your username to begin sending messages.");
    }

    private void start() {
        thread = new Thread(this);
        thread.start();
    }

    private void runClient() throws IOException {
        selector.select();

        Iterator keys = this.selector.selectedKeys().iterator();
        while (keys.hasNext()) {
            SelectionKey key = (SelectionKey) keys.next();
            keys.remove();

            if (!key.isValid()) {
                continue;
            }

            if (key.isReadable()) {
                this.read();
            } else if (key.isWritable()) {
                this.write();
            }
        }
    }

    private void write() throws IOException {
        Iterator<byte[]> items = pendingData.iterator();
        while (items.hasNext()) {
            byte[] item = items.next();
            items.remove();
            channel.write(ByteBuffer.wrap(item));
        }
    }

    private void read() throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.clear();
        int numRead = -1;
        try {
            numRead = channel.read(buffer);
        } catch (IOException e) {
            err("Failed to read from Server: " + channel.getRemoteAddress());
        }

        if (numRead == -1) {
            err("Connection closed by Server: " + channel.getRemoteAddress());
            channel.close();
            return;
        }

        byte[] data = new byte[numRead];
        System.arraycopy(buffer.array(), 0, data, 0, numRead);
        String s = new String(data, "US-ASCII");
        System.out.println(s);
    }

    public void sendText(String s) throws IOException {
        String t = "text: " + s;
        pendingData.add(t.getBytes());
    }

    public void sendName(String s) {
        String t = "user: " + s;
        pendingData.add(t.getBytes());
    }

    @Override
    public void run() {
        while (true) {
            try {
                runClient();
            } catch (IOException ex) {
                err("Client failed. Shutting down...");
                return;
            }
        }
    }
   
    public String log(String s) {
        System.out.println(s);
        return s;
    }
   
    public String err(String s) {
        System.err.println(s);
        return s;
    }
   
    public static void main(String[] args) {
        try {
            Scanner scanner = new Scanner(System.in);
            TCPClient client = new TCPClient(new InetSocketAddress("127.0.0.1", 10000));
            client.sendName(scanner.nextLine());
            while(true) {
                client.sendText(scanner.nextLine());
            }
        } catch (IOException ex) {
            System.err.println("Unable to connect to server. Client shut down.");
        }
    }
   
}


Sorry for the fact that it is not commented. I'll put them in when I have the energy. Next up, UDP server/client.
TCP Server/Client is pretty much done. Here is a link to download the server/client with documentation.

http://www.fileswap.com/dl/Pt4E3cNkdq/QuickNetwork.zip.html

You need at least java 1.6 for it to work.
LARGE UPDATE AGAIN

Practically all of the TCP Code for the game is done. This time I'm using Serializable which takes the state of an object and compresses it into an array of bytes. I can then send it over a SocketChannel and receive it on the other side.

Server-Side Code (Note* is called in a loop)

Code:
public void runServer() throws IOException, ClassNotFoundException {
        selector.select();

        Iterator keys = selector.selectedKeys().iterator();
        while (keys.hasNext()) {
            SelectionKey key = (SelectionKey) keys.next();

            keys.remove();

            if (!key.isValid()) {
                continue;
            }

            if (key.isAcceptable()) {
                this.accept(key);
            } else if (key.isReadable()) {
                this.read(key);
            } else if (key.isWritable()) {
                this.write(key);
            }
        }
    }

    private void accept(SelectionKey key) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
        SocketChannel channel = serverChannel.accept();
        channel.configureBlocking(false);

        Socket socket = channel.socket();
        SocketAddress remoteAddr = socket.getRemoteSocketAddress();
        log("Connected to: " + remoteAddr);

        ClientInfo client = new ClientInfo();
        clientMap.put(channel, client);
        datagramMap.put(channel.getRemoteAddress(), client);
        channel.register(selector, channel.validOps());
    }

    private void read(SelectionKey key) throws IOException, ClassNotFoundException {
        SocketChannel channel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.clear();
        int numRead = -1;
        try {
            numRead = channel.read(buffer);
        } catch (IOException e) {
            log("Failed to read from: " + channel.socket().getInetAddress());
        }

        if (numRead == -1) {
            datagramMap.remove(channel.getRemoteAddress());
            clientMap.remove(channel);
            channel.close();
            key.cancel();
            return;
        }

        byte[] data = new byte[numRead];
        System.arraycopy(buffer.array(), 0, data, 0, numRead);
        bais = new ByteArrayInputStream(data);
        ois = new ObjectInputStream(bais);
        Object o = ois.readObject();
        if (o instanceof TextPacket) {
            TextPacket t = (TextPacket) o;
            writeTextToEveryone(t);
        }
    }

    private void write(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        ClientInfo client = clientMap.get(channel);
        List<Packet> pendingData = client.getDataList();
        if (pendingData.isEmpty()) {
            return;
        }
        Iterator<Packet> items = pendingData.iterator();
        while (items.hasNext()) {
            Packet packet = items.next();
            items.remove();
            obaos = new OpenByteArrayOutputStream();
            oos = new ObjectOutputStream(obaos);
            oos.writeObject(packet);
            channel.write(ByteBuffer.wrap(obaos.getBuf()));
        }
    }

    public void writeTextToEveryone(TextPacket packet) throws IOException {
        Iterator i = clientMap.keySet().iterator();
        while (i.hasNext()) {
            SocketChannel curChannel = (SocketChannel) i.next();
            clientMap.get(curChannel).addData(packet);
        }
    }

Client-Side Code (Note* also called in a loop)

Code:
public void runClient() throws IOException, ClassNotFoundException {
        selector.select();

        Iterator keys = selector.selectedKeys().iterator();
        while (keys.hasNext()) {
            SelectionKey key = (SelectionKey) keys.next();
            keys.remove();

            if (!key.isValid()) {
                continue;
            }

            if (key.isReadable()) {
                this.read();
            } else if (key.isWritable()) {
                this.write();
            }
        }
    }

    private void read() throws IOException, ClassNotFoundException {
        ByteBuffer buffer = ByteBuffer.allocate(Constants.BYTE_CAPACITY);
        buffer.clear();
        int numRead = -1;
        try {
            numRead = socketChannel.read(buffer);
        } catch (IOException e) {
        }

        if (numRead == -1) {
            socketChannel.close();
            datagramChannel.close();
            selector.close();
            return;
        }

        byte[] data = new byte[numRead];
        System.arraycopy(buffer.array(), 0, data, 0, numRead);
        bais = new ByteArrayInputStream(data);
        ois = new ObjectInputStream(bais);
        Object o = ois.readObject();
        if (!(o instanceof Packet)) {
            ois.close();
            return;
        }
        if (o instanceof TextPacket) {
            TextPacket packet = (TextPacket) o;
            // TODO Do stuff with the TextPacket
        }
    }

    private void write() throws IOException {
        Iterator<Packet> packets = pendingData.iterator();
        while (packets.hasNext()) {
            Packet nextPacket = packets.next();
            packets.remove();
            obaos = new OpenByteArrayOutputStream();
            oos = new ObjectOutputStream(obaos);
            oos.writeObject(nextPacket);
            socketChannel.write(ByteBuffer.wrap(obaos.getBuf()));
        }
    }

The Packet class that is the superclass of TextPacket

Code:
package network.packets;

import java.io.Serializable;

public class Packet implements Serializable {

    String username;

    public Packet(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }
}

The TextPacket class that is actually sent

Code:
package network.packets;

import java.io.Serializable;
import java.util.Objects;

public class TextPacket extends Packet implements Serializable {
   
    private String message;
    private String channel;
   
    public TextPacket(String message, String channel, String username) {
        super(username);
        this.message = message;
        this.channel = channel;
    }

    public String getChannel() {
        return channel;
    }

    public String getMessage() {
        return message;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final TextPacket other = (TextPacket) obj;
        if (!Objects.equals(this.message, other.message)) {
            return false;
        }
        if (!Objects.equals(this.channel, other.channel)) {
            return false;
        }
        if (!Objects.equals(this.username, other.username)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 97 * hash + Objects.hashCode(this.message);
        hash = 97 * hash + Objects.hashCode(this.channel);
        hash = 97 * hash + Objects.hashCode(this.username);
        return hash;
    }
   
}
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement