-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from numengames/feat/new-event-system
feat: Implement a new system based on behavior & events instead of on…
- Loading branch information
Showing
44 changed files
with
2,780 additions
and
2,323 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { Folder, Param, $Param, ScriptBehavior } from '@oo/scripting'; | ||
|
||
import InteractionDirector from '../../common/interactions/InteractionDirector'; | ||
|
||
interface BaseEmitterParams { | ||
triggerKey?: string; | ||
interactionMode: string; | ||
triggerDistance?: number; | ||
yInteractionAdjustment?: number; | ||
} | ||
|
||
/** | ||
* Main class to handle the action in the script. | ||
*/ | ||
export default class BaseEmitter extends ScriptBehavior { | ||
static config = { | ||
title: 'Emitter', | ||
tip: 'Use this to launch an event after interacting with the 3D Object', | ||
}; | ||
|
||
@Param({ name: 'Signal sender' }) | ||
private enterSignal = $Param.Signal(); | ||
|
||
@Param({ type: 'boolean', defaultValue: false, name: 'Can emit signals multiple times?' }) | ||
private doesEmitMultipleTimes = false; | ||
|
||
@Folder('Interaction Mode') | ||
@Param({ | ||
type: 'select', | ||
defaultValue: 'Auto', | ||
name: 'Interaction Mode', | ||
options: ['Auto', 'Key'], | ||
}) | ||
private interactionMode = 'Auto'; | ||
@Param({ | ||
type: 'string', | ||
name: 'Trigger key', | ||
visible: (params: BaseEmitterParams) => params.interactionMode === 'Key', | ||
}) | ||
private triggerKey = 'E'; | ||
@Param({ | ||
step: 0.1, | ||
type: 'number', | ||
name: 'Key dialog adjustment', | ||
visible: (params: BaseEmitterParams) => params.interactionMode === 'Key', | ||
}) | ||
private yInteractionAdjustment = 0; | ||
@Param({ | ||
min: 0.1, | ||
step: 0.1, | ||
type: 'number', | ||
defaultValue: 2, | ||
name: 'Trigger distance', | ||
visible: (params: BaseEmitterParams) => params.interactionMode === 'Key', | ||
}) | ||
private triggerDistance = 2; | ||
|
||
/** | ||
* Called when the script is ready. | ||
*/ | ||
onReady = async () => { | ||
await InteractionDirector.handle(this, () => this.enterSignal.emit()); | ||
}; | ||
} |
86 changes: 86 additions & 0 deletions
86
src/behaviors/emitters/insert-password/InsertPasswordEmitter.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import * as React from 'react'; | ||
import { Folder, Param, $Param, ScriptBehavior, UI } from '@oo/scripting'; | ||
|
||
import InsertPasswordPrompt from './InsertPasswordPrompt.tsx'; | ||
import InteractionDirector from '../../../common/interactions/InteractionDirector'; | ||
|
||
interface InsertPasswordEmitterParams { | ||
triggerKey?: string; | ||
interactionMode: string; | ||
triggerDistance?: number; | ||
yInteractionAdjustment?: number; | ||
} | ||
|
||
/** | ||
* Main class to handle the emitter in the script. | ||
*/ | ||
export default class InsertPasswordEmitter extends ScriptBehavior { | ||
static config = { | ||
title: 'Emitter - Insert Password', | ||
tip: 'Use this to launch an event after solving the password', | ||
}; | ||
|
||
private renderer = UI.createRenderer(); | ||
|
||
@Param({ name: 'Signal sender' }) | ||
private enterSignal = $Param.Signal(); | ||
|
||
@Param({ | ||
type: 'string', | ||
name: 'Master password' | ||
}) | ||
private masterPassword = ''; | ||
|
||
@Param({ type: 'boolean', defaultValue: false, name: 'Can emit signals multiple times?' }) | ||
private doesEmitMultipleTimes = false; | ||
|
||
@Folder('Interaction Mode') | ||
@Param({ | ||
type: 'select', | ||
defaultValue: 'Auto', | ||
name: 'Interaction Mode', | ||
options: ['Auto', 'Key'], | ||
}) | ||
private interactionMode = 'Auto'; | ||
@Param({ | ||
type: 'string', | ||
name: 'Trigger key', | ||
visible: (params: InsertPasswordEmitterParams) => params.interactionMode === 'Key', | ||
}) | ||
|
||
private triggerKey = 'E'; | ||
@Param({ | ||
step: 0.1, | ||
type: 'number', | ||
name: 'Key dialog adjustment', | ||
visible: (params: InsertPasswordEmitterParams) => params.interactionMode === 'Key', | ||
}) | ||
private yInteractionAdjustment = 0; | ||
@Param({ | ||
min: 0.1, | ||
step: 0.1, | ||
type: 'number', | ||
defaultValue: 2, | ||
name: 'Trigger distance', | ||
visible: (params: InsertPasswordEmitterParams) => params.interactionMode === 'Key', | ||
}) | ||
private triggerDistance = 2; | ||
|
||
onReady = async () => { | ||
await InteractionDirector.handle(this, this.showInsertPassword.bind(this)); | ||
}; | ||
|
||
private showInsertPassword() { | ||
this.renderer.render( | ||
<InsertPasswordPrompt | ||
key={new Date().getTime()} | ||
masterPassword={this.masterPassword} | ||
onSuccess={this.handleSolvedPassword} | ||
/> | ||
); | ||
} | ||
|
||
private handleSolvedPassword = () => { | ||
this.passwordSolvedSignal.emit() | ||
} | ||
} |
162 changes: 162 additions & 0 deletions
162
src/behaviors/emitters/insert-password/InsertPasswordPrompt.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import * as React from 'react'; | ||
import { useState } from 'react'; | ||
|
||
interface PasswordPromptProps { | ||
onSuccess: () => void; | ||
masterPassword: string; | ||
} | ||
|
||
const styles = ` | ||
.ask-for-password-wrapper { | ||
background: radial-gradient(circle, rgba(0, 255, 255, 0.1), transparent 60%), | ||
radial-gradient(circle at top left, rgba(0, 255, 255, 0.15), transparent 70%), | ||
radial-gradient(circle at bottom right, rgba(0, 255, 255, 0.15), transparent 70%); | ||
background-color: #282c34; | ||
position: fixed; | ||
border: 1px solid #3e3e3e; | ||
border-radius: 15px; | ||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5); | ||
padding: 40px; | ||
left: 75%; | ||
top: 50%; | ||
transform: translate(-50%, -50%); | ||
width: 300px; | ||
overflow: hidden; | ||
} | ||
.ask-for-password-wrapper > button { | ||
position: absolute; | ||
right: 10px; | ||
top: 10px; | ||
border: none; | ||
background: none; | ||
color: #f8f8f8; | ||
font-size: 20px; | ||
cursor: pointer; | ||
} | ||
.ask-for-password-wrapper > button:hover { | ||
color: #416792; | ||
} | ||
.ask-for-password-form { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
position: relative; | ||
z-index: 1; | ||
} | ||
.ask-for-password-form > h1 { | ||
font-size: 24px; | ||
color: #b3eaff; | ||
margin-bottom: 20px; | ||
text-shadow: 0 0 5px rgba(179, 234, 255, 0.7); | ||
} | ||
#ask-for-password-input { | ||
background-color: #1c1c1c; | ||
border: 2px solid #3e3e3e; | ||
border-radius: 4px; | ||
color: #f8f8f8; | ||
font-size: 16px; | ||
margin-bottom: 20px; | ||
padding: 10px 15px; | ||
transition: border-color 0.3s; | ||
width: 100%; | ||
} | ||
#ask-for-password-input:focus { | ||
border-color: #b3eaff; | ||
outline: none; | ||
} | ||
.ask-for-password-form > button { | ||
background: linear-gradient(135deg, #00d4ff, #00a6ff); | ||
border: none; | ||
border-radius: 4px; | ||
color: black; | ||
font-weight: bold; | ||
cursor: pointer; | ||
font-size: 18px; | ||
padding: 10px 15px; | ||
transition: background-color 0.3s ease, box-shadow 0.3s ease; | ||
width: 100%; | ||
box-shadow: 0 0 15px rgba(0, 255, 255, 0.4); | ||
} | ||
.ask-for-password-form > button:hover { | ||
background: linear-gradient(135deg, #00a6ff, #00d4ff); | ||
box-shadow: 0 0 25px rgba(0, 255, 255, 0.8); | ||
} | ||
.ask-for-password-form > span { | ||
color: #ff4d4d; | ||
margin-top: 20px; | ||
display: block; | ||
font-size: 16px; | ||
} | ||
`; | ||
|
||
const InsertPasswordPrompt = ({ | ||
onSuccess, | ||
masterPassword, | ||
}: PasswordPromptProps): JSX.Element | null => { | ||
const [password, setPassword] = useState(''); | ||
const [isVisible, setIsVisible] = useState(true); | ||
const [errorMessage, setErrorMessage] = useState(''); | ||
|
||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { | ||
setPassword(event.target.value); | ||
}; | ||
|
||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => { | ||
event.preventDefault(); | ||
if (password === masterPassword) { | ||
setIsVisible(false); | ||
onSuccess(); | ||
} else { | ||
setPassword(''); | ||
setErrorMessage('Incorrect password'); | ||
} | ||
}; | ||
|
||
const handleClose = () => { | ||
setIsVisible(false); | ||
}; | ||
|
||
if (!isVisible) return null; | ||
|
||
return ( | ||
<> | ||
<div className="ask-for-password-wrapper" aria-labelledby="password-prompt-title"> | ||
<button onClick={handleClose} aria-label="Close password prompt"> | ||
<span> x </span> | ||
</button> | ||
<form className="ask-for-password-form" aria-label="Password prompt form"> | ||
<h1 id="password-prompt-title">Enter the Password</h1> | ||
<input | ||
type="password" | ||
name="password" | ||
id="ask-for-password-input" | ||
value={password} | ||
onChange={handleChange} | ||
placeholder="Type your password here" | ||
aria-label="Password input" | ||
/> | ||
<button onClick={handleClick} aria-label="Unlock button"> | ||
<span> Unlock </span> | ||
</button> | ||
{errorMessage && ( | ||
<span role="alert" aria-live="assertive"> | ||
{errorMessage} | ||
</span> | ||
)} | ||
</form> | ||
</div> | ||
<style>{styles}</style> | ||
</> | ||
); | ||
}; | ||
|
||
export default InsertPasswordPrompt; |
Oops, something went wrong.