Raised This Month: $ Target: $400
 0% 

Add 3 sounds to AMX Custom Votes (jtp10181)


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Curryking
Veteran Member
Join Date: Jun 2004
Location: 51.22°N / 6.77°E
Old 01-07-2006 , 23:13   Add 3 sounds to AMX Custom Votes (jtp10181)
Reply With Quote #1

Hi,

I want to add 3 sounds to the Custom Votes v0.1 by jtp10181

1. vote_now.wav - when the vote has started
2. vote_failed.wav - when a vote has failed
3. vote_passed.wav - when a vote has passed

Can't be that difficult when your well versed in scripting, for me it's seems quite undoable. So I'm counting on someones help. I would appreciate any help.

Cheers, Curry

Code:
/* AMX Mod X script. * *   AMXx Custom Votes (amx_customvotes.sma) *   Copyright (C) 2003-2004  Eric Lidman / jtp10181 * *   This program is free software; you can redistribute it and/or *   modify it under the terms of the GNU General Public License *   as published by the Free Software Foundation; either version 2 *   of the License, or (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. * *   In addition, as a special exception, the author gives permission to *   link the code of this program with the Half-Life Game Engine ("HL *   Engine") and Modified Game Libraries ("MODs") developed by Valve, *   L.L.C ("Valve"). You must obey the GNU General Public License in all *   respects for all of the code used other than the HL Engine and MODs *   from Valve. If you modify this file, you may extend this exception *   to your version of the file, but you are not obligated to do so. If *   you do not wish to do so, delete this exception statement from your *   version. * **************************************************************************** * *   Version 0.1 - Date: 07/10/2004 * *   Created by: jtp10181 <[email protected]> *   Homepage: <a href="http://www.jtpage.net" target="_blank" rel="nofollow noopener">http://www.jtpage.net</a> * **************************************************************************** * *  This plugin allows you to add a custom vote for virtually anything.  All *  you need to know is the cvar or server command to turn the plugin on and off. * *  Features: * *   - Add any amount of votes to the config file and it loads them on map changes *   - Nearly all aspects of the votes are customizable *   - Different timer/delay modes to suit your needs *   - Reads the vote delay from the standard AMXx cvar setting *   - Easy console menu system for admins to start votes and change settings *   - Matrix style jumping is done entirely by this vote plugin because only a CVAR needs to be changed *   - Config file included for all plugins written or maintained by me * *  Admin Commands: * *    amx_custvote       - Console menu system for changing vote settings * *   Examples: *   amx_custvote        - Shows the console admin vote menu *   amx_custvote #2     - Starts vote #2 *   amx_custvote matrix - Starts the vote with trigger "matrix" *   amx_custvote #2 off - Disable public voting for #2 *   amx_custvote #2 save    - Save the current public voting status as the default for #2 *   amx_custvote #2 on save - Enable public voting for #2 AND save that as the default * *    amx_custcancelvote     - Cancels current voting session * *  Client Command: * *    say vote_<trigger>  - Starts a vote if public voting is enabled * *  Config File: This should be located at <configs_dir>/custvote.cfg *       Here is an example config file that could be used * **************************************************************************** *  CONFIG FILE EXAMPLE BEGIN **************************************************************************** //Config file for amx_customvotes.sma //Created by jtp10181 //This file belongs at <configs_dir>/custvote.cfg //Sample Config Entry //The vote can be activated by saying "vote_trigger" //[trigger] //D "Description used in results" //Q "Vote question?" //Y "YES question choice" //N "NO Answer choise" //H "Help line to be displayed if vote succeeds" //The following two can be cvars settings or any server command //YC    "server command to run if vote passes" //NC    "server command to run if vote failes" //The following can be set to different modes and is optional //  * -1 - No timer checking //  *  0 - Use plugin global timer (default if not set) //  *  1 - Use server global timer (same as adminvote) //  *  2 - Use vote specific timer //TM    0 [matrix] D   "Matrix Jumping" Q   "Do you want Matrix style jumping?" Y   "Hand me the red pill!" N   "No thanks" YC  "sv_airaccelerate -15" NC  "sv_airaccelerate 10" [hook] D   "Grappling Hook" Q   "Allow the Grappling Hook?" Y   "Yes, I want to Hook N   "No, the Hook is stupid" YC  "sv_hook 1" NC  "sv_hook 0" H   "- Say /hook for help" TM  2 **************************************************************************** *  CONFIG FILE EXAMPLE END **************************************************************************** * *  CVARs: Paste the following into your amxx.cfg to change defaults. *       You must uncomment cvar lines for them to take effect * **************************************************************************** *  CVAR CONFIG BEGIN **************************************************************************** // ******************  Custom Vote Settings  ****************** //Custom Vote Admin Override (CVAO) // 0 - admins are forced to obey vote timers // 1 - vote timers are ignored for the console admin commands //amx_cvao 0 **************************************************************************** *  CVAR CONFIG END **************************************************************************** * *  Changelog: * *  v0.2 - JTP10181 - 05/09/04 *   - Allowed more chars to be read from config file *   - Made use of plugin_cfg native to delay the reading of the config file * *  v0.1 - JTP10181 - 07/10/04 *   - First Public Release * *  Thanks to the AMXX Dev Team for the orginal adminvote plugin. *  The core voting code for this plugin was borrowed from there. * **************************************************************************/ #define MAX_VOTES 32 //Language Strings new g_alredyVoting[]= "There is already a vote in progress" new g_notAllowed[] = "That vote will be allowed in %d:%02d minute(s)." // %d(1) - minutes, %d(2) - seconds new g_votingStarted[] = "Voting has been started..." new g_votingFailed[] = "Failed" new g_votingSuccess[] = "Succeeded" new g_votingTied[] = "Tied" new g_playerTag[] = "PLAYER" new g_adminTag[] = "ADMIN" /*********************************************************************************** *                                                                                  * *  *end* customizable section of code. other changes can be done with the cvars    * *                                                                                  * ************************************************************************************/ #include <amxmodx> #include <amxmisc> //General use Vars new g_voteCount[2],vaultkey[32] new g_TotalVoters, g_cmenu new TotalVotes = -1,votenum new Float:VoteTimer[MAX_VOTES + 1] new bool:Voting = false new votekeys = (1<<0)|(1<<1) new g_Usage[] = "Usage:  amx_custvote [## or trigger] [on|off|save|vote] [save]" //Vote Config Arrays new vote_trigger[MAX_VOTES][128] new vote_description[MAX_VOTES][128] new vote_question[MAX_VOTES][128] new vote_AnsYes[MAX_VOTES][128] new vote_AnsNo[MAX_VOTES][128] new vote_YesCmd[MAX_VOTES][128] new vote_NoCmd[MAX_VOTES][128] new vote_HelpLine[MAX_VOTES][128] new vote_TimerMode[MAX_VOTES] new bool:vote_Enabled[MAX_VOTES] new bool:vote_BadLoad[MAX_VOTES] public plugin_init() {     register_plugin("Easy Custom Votes","0.2","JTP10181")     register_menucmd(register_menuid("Vote: ") ,votekeys,"voteCount")     register_clcmd("say","HandleSay")     register_concmd("amx_custvote","cmdVote",ADMIN_VOTE,"- system for changing custom vote settings")     register_concmd("amx_custcancelvote","cmdCancelVote",ADMIN_VOTE,"- cancels current custom vote")     register_cvar("amx_cvao","0")     g_cmenu = colored_menus() } public plugin_cfg() {     load_config()     check_config() } public load_config() {     new filename[128],dataread[128],flag[4],tempdata[128]     new linenum,textlen,triggerend     new bool:perror = false     get_configsdir(filename,127)     format(filename,127,"%s/custvote.cfg",filename)     if (!file_exists(filename)) {         log_amx("%s not found, no custom votes loaded.",filename)         return PLUGIN_CONTINUE     }     while (read_file(filename,linenum,dataread,127,textlen)) {         linenum++         perror = false         triggerend = contain(dataread,"]")         if (equal(dataread[0],"//",2)) {             //Do nothing because its a comment         }         else if (equal(dataread[0],"[",1) && triggerend > 0 ) {             TotalVotes++             if (TotalVotes >= MAX_VOTES) {                 log_amx("MAX_VOTES of %d exceeded, no more votes will be loaded.",MAX_VOTES)                 return PLUGIN_CONTINUE             }             copy(vote_trigger[TotalVotes],triggerend - 1,dataread[1])         }         else if (!equal(dataread,"") && TotalVotes >= 0) {             parse(dataread,flag,3,tempdata,127)             remove_quotes(tempdata)             if (equal(flag,"D")) {                 if (equal(tempdata,"")) perror = true                 else copy(vote_description[TotalVotes],127,tempdata)             }             else if (equal(flag,"Q")) {                 if (equal(tempdata,"")) perror = true                 else copy(vote_question[TotalVotes],127,tempdata)             }             else if (equal(flag,"Y")) {                 if (equal(tempdata,"")) perror = true                 else copy(vote_AnsYes[TotalVotes],127,tempdata)             }             else if (equal(flag,"N")) {                 if (equal(tempdata,"")) perror = true                 else copy(vote_AnsNo[TotalVotes],127,tempdata)             }             else if (equal(flag,"YC")) {                 if (equal(tempdata,"")) perror = true                 else copy(vote_YesCmd[TotalVotes],127,tempdata)             }             else if (equal(flag,"NC")) {                 if (equal(tempdata,"")) perror = true                 else copy(vote_NoCmd[TotalVotes],127,tempdata)             }             else if (equal(flag,"H")) {                 if (equal(tempdata,"")) perror = true                 else copy(vote_HelpLine[TotalVotes],127,tempdata)             }             else if (equal(flag,"TM")) {                 if (equal(tempdata,"")) perror = true                 else vote_TimerMode[TotalVotes] = str_to_num(tempdata)             }             if (perror)                 log_amx("Parse error on line %d of custvote.cfg",linenum)         }     }     TotalVotes++     log_amx("[AMXX] Total of %d custom votes read from config file.",TotalVotes)     return PLUGIN_CONTINUE } check_config() {     new x     for (x = 0; x < TotalVotes; x++ ) {         vote_Enabled[x] = true         if (equal(vote_trigger[x],"")) {             vote_Enabled[x] = false             vote_BadLoad[x] = true             log_amx("BAD LOAD for vote #%d - No trigger found",x + 1)         }         if (equal(vote_description[x],"")) {             copy(vote_description[x],15,vote_trigger[x])         }         if (equal(vote_question[x],"")) {             format(vote_question[x],63,"Vote for %s",vote_trigger[x])         }         if (equal(vote_AnsYes[x],"")) {             copy(vote_AnsYes[x],63,"Yes")         }         if (equal(vote_AnsNo[x],"")) {             copy(vote_AnsNo[x],63,"No")         }         if (equal(vote_YesCmd[x],"") || equal(vote_NoCmd[x],"")) {             vote_Enabled[x] = false             vote_BadLoad[x] = true             log_amx("BAD LOAD for vote ^"%s^" - Missing server command",vote_trigger[x][0] ? vote_trigger[x] : "UNKNOWN")         }         format(vaultkey,31,"cv.%s",vote_trigger[x])         if (!vote_BadLoad[x] && vaultdata_exists(vaultkey)) {             new tmpvault[16]             get_vaultdata(vaultkey, tmpvault, 15)             if (equali(tmpvault,"off")) {                 vote_Enabled[x] = false             }             else if (equali(tmpvault,"on")) {                 vote_Enabled[x] = true             }         }     } } public HandleSay(id) {     new Speech[192],trigger[32],x,TimeLeft     read_args(Speech,192)     remove_quotes(Speech)     for (x = 0; x < TotalVotes; x++ ) {         format(trigger,31,"vote_%s",vote_trigger[x])         if (vote_Enabled[x] && equal(Speech,trigger)) {             if(get_cvar_float("amx_last_voting") > get_gametime() || Voting) {                 client_print(id,print_chat,g_alredyVoting)                 return PLUGIN_HANDLED             }             switch(vote_TimerMode[x]) {                 case 0: TimeLeft = TimerCheck(MAX_VOTES)                 case 1: TimeLeft = TimerCheck(-1)                 case 2: TimeLeft = TimerCheck(x)             }             if (TimeLeft > 0) {                 client_print(id,print_chat,g_notAllowed,TimeLeft / 60, TimeLeft % 60)                 return PLUGIN_HANDLED             }             votenum = x             startVote(id)         }     }     return PLUGIN_CONTINUE } TimerCheck(timer){     new Float:CurTime = get_gametime()     new Float:vote_delay = get_cvar_float("amx_vote_delay")     new Float:vote_time = get_cvar_float("amx_vote_time") + 2.0     new Float:last_voting     new TimeLeft = 0     if (timer == -1)         last_voting = get_cvar_float("amx_last_voting")     else         last_voting = VoteTimer[timer]     if(last_voting && last_voting + vote_delay >= CurTime){         TimeLeft = floatround((last_voting + vote_delay) - CurTime)     }     else {         if (timer == -1)             set_cvar_float("amx_last_voting", CurTime + vote_time)         else             VoteTimer[timer] = CurTime + vote_time     }     return TimeLeft } public cmdVote(id,level,cid) {     if (!cmd_access(id,level,cid,1))         return PLUGIN_HANDLED     new arg1[32],arg2[32],arg3[32],TimeLeft     new tempvnum = -1     new numofargs = read_argc() - 1     if (numofargs > 0) {         read_argv(1,arg1,31)         read_argv(2,arg2,31)         read_argv(3,arg3,31)     }     if (numofargs == 0) {         console_print(id,"AMXX Custom Votes^n")         if (TotalVotes <= 0) {             console_print(id,"No votes loaded from custvote.cfg^n")         }         else {             console_print(id,"%2s | %-10s | %-24s | %s","#","Trigger","Description","Status")             console_print(id,"----------------------------------------------------")             for (new x=0; x < TotalVotes; x++) {                 console_print(id,"%2d | %-10s | %-24s | %s%s",x + 1,vote_trigger[x],vote_description[x],vote_Enabled[x] ? "ON" : "OFF", vote_BadLoad[x] ? " - BAD LOAD" : "")             }             console_print(id,"")             console_print(id,g_Usage)             console_print(id,"")         }         return PLUGIN_HANDLED     }     if(get_cvar_float("amx_last_voting") > get_gametime() || Voting) {         console_print(id,g_alredyVoting)         return PLUGIN_HANDLED     }     if (equal("#",arg1,1)) {         tempvnum = str_to_num(arg1[1]) - 1         if (tempvnum < 0 || tempvnum >= TotalVotes) {             console_print(id,g_Usage)             console_print(id,"[AMXX] Invalid selection, please pick a valid vote from 1 - %d",TotalVotes)             return PLUGIN_HANDLED         }     }     else {         for (new x=0; x < TotalVotes; x++) {             if (equali(arg1,vote_trigger[x])) {                 tempvnum = x             }         }         if (tempvnum == -1) {             console_print(id,g_Usage)             console_print(id,"[AMXX] Invalid trigger selection, please check the list and try again")             return PLUGIN_HANDLED         }     }     if (!get_cvar_num("amx_cvao")) {         switch(vote_TimerMode[tempvnum]) {             case 0: TimeLeft = TimerCheck(MAX_VOTES)             case 1: TimeLeft = TimerCheck(-1)             case 2: TimeLeft = TimerCheck(tempvnum)         }         if (TimeLeft > 0) {             console_print(id,g_notAllowed,TimeLeft / 60, TimeLeft % 60)             return PLUGIN_HANDLED         }     }     if (numofargs == 1) {         if (vote_BadLoad[tempvnum]) {             console_print(id,"[AMXX] Voting for ^"%s^" cannot be started - BAD LOAD",vote_trigger[tempvnum][0] ? vote_trigger[tempvnum] : "UNKNOWN")         }         else {             votenum = tempvnum             startVote(id)         }     }     else if (numofargs == 2 || numofargs == 3) {         new bool:save = false         if (!equali(arg3,"") && !equali(arg3,"save")) {             console_print(id,"[AMXX] Invalid third argument")             console_print(id,g_Usage)             return PLUGIN_HANDLED         }         if (equali(arg2,"save")) {             save = true         }         else if (equali(arg2,"on")) {             if (vote_Enabled[tempvnum]) {                 console_print(id,"[AMXX] Public voting for ^"%s^" is already enabled",vote_trigger[tempvnum])             }             else {                 if (vote_BadLoad[tempvnum]) {                     console_print(id,"[AMXX] Public voting for ^"%s^" cannot be enabled - BAD LOAD",vote_trigger[tempvnum])                 }                 else {                     vote_Enabled[tempvnum] = true                     console_print(id,"[AMXX] Public voting for ^"%s^" has been enabled",vote_trigger[tempvnum])                 }             }             if (equali(arg3,"save") && vote_Enabled[tempvnum]) {                 save = true             }         }         else if (equali(arg2,"off")) {             if (!vote_Enabled[tempvnum]) {                 console_print(id,"[AMXX] Public voting for ^"%s^" is already disabled",vote_trigger[tempvnum])             }             else {                 vote_Enabled[tempvnum] = false                 console_print(id,"[AMXX] Public voting for ^"%s^" has been disabled",vote_trigger[tempvnum])             }             if (equali(arg3,"save") && !vote_Enabled[tempvnum]) {                 save = true             }         }         else if (equali(arg2,"vote")) {             if (vote_BadLoad[tempvnum]) {                 console_print(id,"[AMXX] Voting for ^"%s^" cannot be started - BAD LOAD",vote_trigger[tempvnum][0] ? vote_trigger[tempvnum] : "UNKNOWN")             }             else {                 votenum = tempvnum                 startVote(id)             }         }         else {             console_print(id,"[AMXX] Invalid second argument")             console_print(id,g_Usage)             return PLUGIN_HANDLED         }         if (save) {             if (vote_BadLoad[tempvnum]) {                 console_print(id,"[AMXX] Public voting satus for ^"%s^" cannot be saved - BAD LOAD",vote_trigger[tempvnum])             }             else if (vote_Enabled[tempvnum]) {                 format(vaultkey,31,"cv.%s",vote_trigger[tempvnum])                 set_vaultdata(vaultkey,"ON")                 console_print(id,"[AMXX] Public voting for ^"%s^" has been saved as ON",vote_trigger[tempvnum])             }             else  {                 format(vaultkey,31,"cv.%s",vote_trigger[tempvnum])                 set_vaultdata(vaultkey,"OFF")                 console_print(id,"[AMXX] Public voting for ^"%s^" has been saved as OFF",vote_trigger[tempvnum])             }         }     }     else {         console_print(id,"[AMXX] Too many arguments supplied")         console_print(id,g_Usage)     }     return PLUGIN_HANDLED } public cmdCancelVote(id,level,cid){     if (!cmd_access(id,level,cid,1))         return PLUGIN_HANDLED     if (task_exists(99578788, 1)) {         new authid[35],name[32]         get_user_authid(id,authid,34)         get_user_name(id,name,31)         log_amx("Vote: ^"%s<%d><%s><>^" canceled vote for ^"%s^"", name,get_user_userid(id),authid,vote_description[votenum])         switch(get_cvar_num("amx_show_activity")) {             case 2: client_print(0,print_chat,"%s %s: canceled vote for ^"%s^"", (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag, name,vote_description[votenum])             case 1: client_print(0,print_chat,"%s: canceled vote for ^"%s^"", (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag,vote_description[votenum])             case 0: client_print(0,print_chat,"Voting for ^"%s^" has been canceled",vote_description[votenum])         }         console_print(id,"[AMXX] Voting for ^"%s^" has been canceled",vote_description[votenum])         remove_task( 99578788 , 1 )         switch(vote_TimerMode[votenum]) {             case 0: VoteTimer[MAX_VOTES] = get_gametime()             case 1: set_cvar_float("amx_last_voting", get_gametime())             case 2: VoteTimer[votenum] = get_gametime()         }         Voting = false     }     else         console_print(id, "[AMXX] There is no custom voting session to cancel." )     return PLUGIN_HANDLED } public startVote(id) {     new authid[35],name[32]     get_user_authid(id,authid,34)     get_user_name(id,name,31)     Voting = true     log_amx("Vote: ^"%s<%d><%s><>^" vote started (vote ^"%s^") (option#1 ^"%s^") (option#2 ^"%s^")",         name,get_user_userid(id),authid,vote_description[votenum],vote_AnsYes[votenum],vote_AnsNo[votenum])     switch(get_cvar_num("amx_show_activity")) {         case 2: client_print(0,print_chat,"%s %s: activated vote for %s",             (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag,name, vote_description[votenum] )         case 1: client_print(0,print_chat,"%s: activated vote for %s",             (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag, vote_description[votenum])     }     new menu_msg[256]     format(menu_msg,255, g_cmenu ? "\yVote: %s\w^n^n1.  %s^n2.  %s" : "Vote: %s^n^n1.  %s^n2.  %s",vote_question[votenum],vote_AnsYes[votenum],vote_AnsNo[votenum])     new Float:vote_time = get_cvar_float("amx_vote_time") + 2.0     show_menu(0,votekeys,menu_msg,floatround(vote_time))     console_print(id, g_votingStarted )     g_voteCount = {0,0}     g_TotalVoters = 0     set_task(vote_time,"checkVotes", 99578788 )     return PLUGIN_HANDLED } public checkVotes() {     set_hudmessage(63,187,239, -1.0, 0.70, 2, 0.02, 10.0, 0.01, 0.1, 17)     new voteresult[32],hudmess[256]     if (g_voteCount[0] < g_voteCount[1] ){         copy(voteresult,31,g_votingFailed)         client_print(0,print_chat,"Voting for %s %s",vote_description[votenum],voteresult)         server_cmd(vote_NoCmd[votenum])     }     else if (g_voteCount[0] > g_voteCount[1] ){         copy(voteresult,31,g_votingSuccess)         client_print(0,print_chat,"Voting for %s %s %s",vote_description[votenum],voteresult,vote_HelpLine[votenum])         server_cmd(vote_YesCmd[votenum])     }     else {         copy(voteresult,31,g_votingTied)         client_print(0,print_chat,"Voting for %s %s",vote_description[votenum],voteresult)     }     log_amx("Vote: %s (yes ^"%d^") (no ^"%d^") (description ^"%s^")",voteresult,g_voteCount[0],g_voteCount[1],vote_description[votenum])     format(hudmess,255,"Voting for %s %s^n^n%d votes for: %s^n%d votes for: %s^n^n%d Total eligible voters",         vote_description[votenum],voteresult,g_voteCount[0],vote_AnsYes[votenum],g_voteCount[1],vote_AnsNo[votenum],g_TotalVoters)     show_hudmessage(0,hudmess)     Voting = false     return PLUGIN_CONTINUE } public voteCount(id,key){     if ( get_cvar_num("amx_vote_answers") ) {         new name[32]         get_user_name(id,name,31)         client_print(0,print_chat,"%s voted for option #%d",name,key+1)     }     ++g_voteCount[key]     ++g_TotalVoters     return PLUGIN_HANDLED }
__________________
Full speed - no brakes!
Curryking is offline
Brad
AMX Mod X Team Member
Join Date: Jun 2004
Old 01-13-2006 , 08:01  
Reply With Quote #2

Curryking: I'd suggest you ask jtp to add it to the plugin within that thread. Sounds like it may be useful to others.
Brad is offline
Curryking
Veteran Member
Join Date: Jun 2004
Location: 51.22°N / 6.77°E
Old 01-13-2006 , 09:47  
Reply With Quote #3

Already got a PM from Kraugh with an attached amx_customvotes.sma including the changes. Tryed it out and it works fine. Thanks again Kraugh!!

For those who might also be interested in these changes I attached the sma and the sounds.

Curry
Attached Files
File Type: zip amx_customvotes.zip (49.5 KB, 129 views)
__________________
Full speed - no brakes!
Curryking is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 16:11.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode