Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audio Manager #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/client/wz_client/
/node_modules/
/client/bundle.js
/.vscode/
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this VS config file here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest I don't know. He is on my .gitignore. Gotta remove for the next commit

"favorites.resources": [
"src\\server\\server.js"
]
}
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,33 @@
* `npm install`
* `npm run local` to start the application with inspectable client code.
* `npm run dev` to start the application with minified IIFE client code.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my comment on the RZ thread. I don't think it should be part of the README.


## Ragezone Post

* Hi all,

* After futzing around with the physics, I've come to realize that replicating the physics from the original client will be a much harder task than I anticipated. As such, I will have to slow down development and take time to do research and reverse engineer (as best as possible) the physics. You won't see many updates in the near future, but I assure you all that I am still actively working on this project.

* Additionally, because I spent a lot of time working on the client, I acknowledge that some very important things are lacking: documentation and unit tests. These will be added soon.

* In lieu of updates, I am opening up the project for anyone to clone and play around with. See it here: https://github.com/johncintron/nodin.

* Edit: Answers to what I suspect will be FAQs:

* How do I get past the login screen?
* Go in the developer console and enter: LoginState.enterGame(); You can also move up the login map by mutating the Camera.y attribute.

* How do I switch maps?
* MapleMap.load(id); where id is the map id you want to load.

* How do I attach equips to the character?
* MyCharacter.attachEquip(slot, id); where slot is the equip slot and id is the equip id.

* How do I spawn another player?
* MapleCharacter.fromOpts(obj).then(m => MapleMap.characters.push(m));

* Why no WebGL?
* I ditched Phaser because it was too heavy and some MapleStory-specific things were hard to implement using Phaser. Implementing the rendering engine in WebGL would have taken me forever and the game as it stands today runs at 60 FPS on Firefox and Chrome with an i7 processor.

* If anyone wishes to contribute, feel free to PM me and I will add you as a collaborator. I welcome all pull requests!
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"PORT": 8000,
"PORT": 8100,
"SERVER_WZ_ROOT_DIR": "./wz_server/"
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 22 additions & 1 deletion src/client/audiomanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import WZManager from './wzmanager';

const AudioManager = {};

AudioManager.playBGM = async function(name) {
var musicVolume = 1;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not recommended to use var. Try using const instead

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct. Take a look at this style guide: https://github.com/airbnb/javascript.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an addendum, I don't recommend storing these variables at the module level. I prefer assigning these variables to the AudoManager object.

var SFXVolume = 1;

AudioManager.playBGM = async function (name) {
if (name !== this.bgmName) {
if (!!this.bgm) {
this.bgm.pause();
Expand All @@ -13,11 +16,29 @@ AudioManager.playBGM = async function(name) {
return;
}
const [filename, child] = name.split('/');
console.log(filename, child);
const wzNode = await WZManager.get(`Sound.wz/${filename}.img/${child}`);
this.bgm = wzNode.nGetAudio();
this.bgm.loop = true;
this.bgm.play();

//Debug
this.setMusicVolume(0.01);
this.setSFXVolume(0.01);
}
};

AudioManager.setMusicVolume = async function (vol) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The async is not necessary because you're not using await in the body of the function. Also, don't do type checking here; it's an antipattern and the caller is expected to pass a number.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, I was trying to make some sort of validation

if (typeof (vol) === 'number') {
this.musicVolume = vol;
this.bgm.volume = this.musicVolume;
}
}

AudioManager.setSFXVolume = async function (vol) {
if (typeof (vol) === 'number') {
this.SFXVolume = vol;
}
}

export default AudioManager;
29 changes: 15 additions & 14 deletions src/client/maplecharacter.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AudioManager from './audiomanager';
import WZManager from './wzmanager';
import DRAW_IMAGE from './drawimage';
import DRAW_TEXT from './drawtext';
Expand Down Expand Up @@ -80,21 +81,21 @@ class MapleCharacter {
await this.setHair(this.hair);
this.setStance(this.stance);
}
async setSkinColor(sc=0) {
async setSkinColor(sc = 0) {
this.head = await WZManager.get(`Character.wz/0001200${sc}.img`);
this.body = await WZManager.get(`Character.wz/0000200${sc}.img`);
this.baseBody = await WZManager.get(`Character.wz/00002000.img`);
this.skinColor = sc;
}
setStance(stance='stand1', frame=0) {
setStance(stance = 'stand1', frame = 0) {
if (!!this.baseBody[stance]) {
this.stance = stance;
this.setFrame(frame);
this.oscillateFrames = stance.startsWith('stand');
this.oscillateFactor = 1;
}
}
setFrame(frame=0, carryOverDelay=0) {
setFrame(frame = 0, carryOverDelay = 0) {
this.frame = !this.baseBody[this.stance][frame] ? 0 : frame;

this.delay = carryOverDelay;
Expand All @@ -107,31 +108,31 @@ class MapleCharacter {
if (!this.oscillateFrames) {
this.setFrame(this.frame + 1, carryOverDelay);
} else {
const nextFrame = this.frame + 1*this.oscillateFactor;
const nextFrame = this.frame + 1 * this.oscillateFactor;
if (!this.baseBody[this.stance][nextFrame]) {
this.oscillateFactor *= -1;
}
const nextOscillatedFrame = this.frame + 1*this.oscillateFactor;
const nextOscillatedFrame = this.frame + 1 * this.oscillateFactor;
this.setFrame(nextOscillatedFrame, carryOverDelay);
}
}
async setFace(face=20000) {
async setFace(face = 20000) {
this.Face = await WZManager.get(`Character.wz/Face/000${face}.img`);
this.face = face;
}
setFaceExpr(faceExpr='blink', faceFrame=0) {
setFaceExpr(faceExpr = 'blink', faceFrame = 0) {
if (!!this.Face[faceExpr]) {
this.faceExpr = faceExpr;
this.setFaceFrame(faceFrame);
}
}
setFaceFrame(faceFrame=0) {
setFaceFrame(faceFrame = 0) {
this.faceFrame = !this.Face[this.faceExpr][faceFrame] ? 0 : faceFrame;
}
advanceFaceFrame() {
this.setFaceFrame(this.faceFrame + 1);
}
async setHair(hair=30030) {
async setHair(hair = 30030) {
this.Hair = await WZManager.get(`Character.wz/Hair/000${hair}.img`);
this.hair = hair;
}
Expand Down Expand Up @@ -214,7 +215,7 @@ class MapleCharacter {
const lu = await WZManager.get('Effect.wz/BasicEff.img/LevelUp');
this.levelUpFrames = lu.nChildren;

PLAY_AUDIO(levelUpAudio);
PLAY_AUDIO(levelUpAudio, AudioManager.SFXVolume);
this.levelingUp = true;
this.levelUpFrame = 0;
this.levelUpDelay = 0;
Expand Down Expand Up @@ -257,8 +258,8 @@ class MapleCharacter {
const twoChars = /.{1,2}/g;
const [hat, faceAcc, ...equips] = this.equips;

const hatVslot = !hat? '' : hat.info.vslot.nValue;
const hatParts = !hat? [] : getParts(hat).filter(isDrawable);
const hatVslot = !hat ? '' : hat.info.vslot.nValue;
Copy link
Owner

@johncintron johncintron Mar 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These ternaries are the only places where VS autoformat is acceptable. See the other comment about style.

const hatParts = !hat ? [] : getParts(hat).filter(isDrawable);
const hatSmapValues = hatParts.reduce((acc, p) => {
try {
const part = p.nTagName === 'uol' ? p.nResolveUOL() : p;
Expand Down Expand Up @@ -309,7 +310,7 @@ class MapleCharacter {
});

const originX = part.origin.nX;
const adjustX = !flipped ? originX : (part.nWidth-originX);
const adjustX = !flipped ? originX : (part.nWidth - originX);
x -= adjustX;
y -= part.origin.nY;

Expand Down Expand Up @@ -432,7 +433,7 @@ class MapleCharacter {
align: 'center',
};
const nameWidth = Math.ceil(MEASURE_TEXT(nameOpts).width + tagPadding);
const nameTagX = Math.round(this.x - camera.x - nameWidth/2);
const nameTagX = Math.round(this.x - camera.x - nameWidth / 2);
DRAW_RECT({
x: nameTagX,
y: Math.floor(this.y - camera.y + offsetFromY),
Expand Down
17 changes: 9 additions & 8 deletions src/client/monster.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AudioManager from './audiomanager';
import WZManager from './wzmanager';
import PLAY_AUDIO from './playaudio';
import DRAW_IMAGE from './drawimage';
Expand Down Expand Up @@ -49,7 +50,7 @@ class Monster {

this.setFrame(!this.stances.fly ? 'stand' : 'fly', 0);
}
loadStance(wzNode={}, stance='stand') {
loadStance(wzNode = {}, stance = 'stand') {
if (!wzNode[stance]) {
return {
frames: [],
Expand All @@ -73,7 +74,7 @@ class Monster {
}
playAudio(name) {
if (!!this.sounds[name]) {
PLAY_AUDIO(this.sounds[name]);
PLAY_AUDIO(this.sounds[name], AudioManager.SFXVolume);
}
}
die() {
Expand All @@ -84,7 +85,7 @@ class Monster {
destroy() {
this.destroyed = true;
}
setFrame(stance, frame=0, carryOverDelay=0) {
setFrame(stance, frame = 0, carryOverDelay = 0) {
if (!this.stances[stance]) {
return;
}
Expand All @@ -101,12 +102,12 @@ class Monster {
this.delay += msPerTick;

if (this.delay > this.nextDelay) {
const hasNextFrame = !!this.stances[this.stance].frames[this.frame+1];
const hasNextFrame = !!this.stances[this.stance].frames[this.frame + 1];
if (!!this.dying && !hasNextFrame) {
this.destroy();
return;
}
this.setFrame(this.stance, this.frame+1, this.delay-this.nextDelay);
this.setFrame(this.stance, this.frame + 1, this.delay - this.nextDelay);
}
}
draw(camera, lag, msPerTick, tdelta) {
Expand All @@ -116,12 +117,12 @@ class Monster {
const originX = currentFrame.nGet('origin').nGet('nX', 0);
const originY = currentFrame.nGet('origin').nGet('nY', 0);

const adjustX = !this.flipped ? originX : (currentFrame.nWidth-originX);
const adjustX = !this.flipped ? originX : (currentFrame.nWidth - originX);

DRAW_IMAGE({
img: currentImage,
dx: this.x-camera.x-adjustX,
dy: this.y-camera.y-originY,
dx: this.x - camera.x - adjustX,
dy: this.y - camera.y - originY,
flipped: !!this.flipped,
});
}
Expand Down
5 changes: 3 additions & 2 deletions src/client/playaudio.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
* @param {Audio} audio - The audio object.
* @param {float} [volume=1] - Loudness of audio.
*/
function PLAY_AUDIO(audio, volume=1) {

function PLAY_AUDIO(audio, vol) {
const concurrentAudio = audio.cloneNode();
concurrentAudio.volume = volume;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change volume to vol? It's a good practice to be explicit in what you want to do, and abbreviating names could bad for readability

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Also, the default parameter is there for a good reason.

concurrentAudio.volume = vol;
concurrentAudio.play();
}

Expand Down
17 changes: 9 additions & 8 deletions src/client/uicommon.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import AudioManager from './audiomanager';
import DRAW_IMAGE from './drawimage';
import GameCanvas from './gamecanvas';
import WZManager from './wzmanager';
import PLAY_AUDIO from './playaudio';
import WZManager from './wzmanager';

const UICommon = {};

UICommon.initialize = async function() {
UICommon.initialize = async function () {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please no whitespace between function and the parentheses.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johncintron according to airbnb styleguide, the space is correct:
space-before-function-paren

const cursor = await WZManager.get('UI.wz/Basic.img/Cursor');

this.cursorImg = cursor[0][0].nGetImage();
Expand All @@ -21,18 +22,18 @@ UICommon.initialize = async function() {
this.hoverAudio = sounds.BtMouseOver.nGetAudio();
};

UICommon.playMouseClickAudio = function() {
PLAY_AUDIO(this.clickAudio);
UICommon.playMouseClickAudio = function () {
PLAY_AUDIO(this.clickAudio, AudioManager.SFXVolume);
};

UICommon.playMouseHoverAudio = function() {
PLAY_AUDIO(this.hoverAudio);
UICommon.playMouseHoverAudio = function () {
PLAY_AUDIO(this.hoverAudio, AudioManager.SFXVolume);
};

UICommon.doUpdate = function(msPerTick) {
UICommon.doUpdate = function (msPerTick) {
};

UICommon.doRender = function(camera, lag, msPerTick, tdelta) {
UICommon.doRender = function (camera, lag, msPerTick, tdelta) {
const clicked = GameCanvas.clicked;
const cursorImg = !clicked ? this.cursorImg : this.cursorDownImg;
const cursorOrigin = !clicked ? this.cursorOrigin : this.cursorDownOrigin;
Expand Down
6 changes: 3 additions & 3 deletions src/client/uilogin.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ UILogin.doUpdate = function(msPerTick, camera) {
this.loginButton.stance = 'normal';

if (this.activeButton === this.loginButton) {
UICommon.playMouseHoverAudio();
UICommon.playMouseHoverAudio(1);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UICommon.playMouseHoverAudio doesn't take any arguments. Not sure why you're passing 1 to it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably forgot to remove, I was using during the test phase

this.loginButton.stance = 'mouseOver';
}
}
Expand All @@ -129,7 +129,7 @@ UILogin.doUpdate = function(msPerTick, camera) {
this.loginButton.stance = 'mouseOver';
const trigger = releasedClick && originallyClickedLoginButton;
if (trigger) {
UICommon.playMouseClickAudio();
UICommon.playMouseClickAudio(1);
console.log('login!');
}
}
Expand All @@ -141,7 +141,7 @@ UILogin.doUpdate = function(msPerTick, camera) {
if (releasedClick && originallyClickedDice && this.canClickDice) {
this.canClickDice = false;
this.updateDice = true;
UICommon.playMouseClickAudio();
UICommon.playMouseClickAudio(1);
}
}

Expand Down