import java.lang.Math; import java.util.*; import java.awt.*; import java.awt.event.*; import java.applet.*; public class CoCchar extends Applet { static Random rnd; static TextArea ta; static Button b_generate; static String s_generate = "Create New Investigator"; static Button b_school; static String s_school = "Extended Schooling: 1 year"; static Button b_age; static String s_age = "Age Investigator: 10 years"; static Button b_summary; static String s_summary = "Summarize Statistics"; static Choice c_era, c_age; static Label l_age; static int rows = 24; static int cols = 80; static String s_STR = "STR"; static String s_CON = "CON"; static String s_DEX = "DEX"; static String s_APP = "APP"; static String s_NA = "NA"; int era; int strength; int dexterity; int intelligence; int constitution; int appearance; int power; int size; int sanity; int education; int idea; int luck; int know; String dmgBonus; int hp; int occupation; int interest; int minAge = 0; int age = 0; int wealth; int income; int dodge; int d(int x) { double f = rnd.nextDouble(); f *= (double) x; int i = (int) f; return 1+i; } String rpad(String s, int n) { while (s.length() < n) { s = " "+s; } return s; } String rpad(int d, int n) { String s = String.valueOf(d); while (s.length() < n) { s = " "+s; } return s; } String damageBonus(int strsiz) { // range limited to initial human statistics if (strsiz < 13) return "-1D6"; if (strsiz < 17) return "-1D4"; if (strsiz < 25) return "none"; if (strsiz < 33) return "+1D4"; return "+1D6"; } String damageBonus(int str, int siz) { return damageBonus(str+siz); } int calcIncome(int wealth) { int income; if (era == 1890) { income = wealth*5000; } else if (era == 1920) { income = wealth*1000+3500; } else { income = wealth*10000+5000; } return income; } void derive() { // derived stats that may vary dmgBonus = damageBonus(strength,size); hp = (int) ((constitution+size+1)/2); dodge = 2*dexterity; know = 5*education; if (know > 99) know = 99; } void summarize() { ta.setText("STR: "+rpad(strength,2)+" DEX: " +rpad(dexterity,2)+" INT: "+rpad(intelligence,2) +" Idea Roll: "+rpad(idea,3)+"%\n"); ta.append("CON: "+rpad(constitution,2)+" APP: " +rpad(appearance,2)+" POW: "+rpad(power,2) +" Luck Roll: "+rpad(luck,3)+"%\n"); ta.append("SIZ: "+rpad(size,2)+" SAN: "+rpad(sanity,2) +" EDU: "+rpad(education,2)+" Know Roll: " +rpad(know,3)+"%\n"); ta.append("Damage Bonus: "+dmgBonus+" Hit Points: " +rpad(hp,2)+"\n"); ta.append("Occupation Points: "+rpad(occupation,3) +" Personal Interest Points: "+rpad(interest,3) +"\n"); ta.append("Age: "+age+" ("+minAge+" minimum) Base Dodge skill: " +rpad(dodge,2)+"%\n"); ta.append(era+"s Income: $"+income); } void generate() { strength = d(6)+d(6)+d(6); dexterity = d(6)+d(6)+d(6); intelligence = 6+d(6)+d(6); constitution = d(6)+d(6)+d(6); appearance = d(6)+d(6)+d(6); power = d(6)+d(6)+d(6); size = 6+d(6)+d(6); sanity = 5*power; education = 3+d(6)+d(6)+d(6); idea = 5*intelligence; luck = 5*power; occupation = 20*education; interest = 10*intelligence; derive(); minAge = 6+education; age = minAge; wealth = d(10); income = calcIncome(wealth); } void school() { int old = know; age++; ta.append("\n Your age is now "+age+"."); if (d(100) <= know) { education++; derive(); ta.append(" Your EDU is now "+education+"."); if (know != old) ta.append(" Your Know roll is " +know+"%"); } interest += 10; ta.append("\n Your personal interest points are now " +interest+"."); } void age10() { int oldKnow = know; age += 10; ta.append("\n Your age is now "+age+". "); education++; derive(); ta.append(" Your EDU is now "+education+"."); if (know != oldKnow) ta.append(" Your Know roll is " +know+"%"); occupation += 20; ta.append("\n Your occupation points are now " +occupation+"."); if (age > 40) { if (c_age.getSelectedItem().equals(s_STR)) { String old = dmgBonus; strength--; ta.append("\n Your STR is now "+strength+"."); derive(); if (! old.equals(dmgBonus)) ta.append("\n Your damage bonus is now "+dmgBonus+"."); if (strength == 1) c_age.remove(s_STR); } else if (c_age.getSelectedItem().equals(s_CON)) { int old = hp; constitution--; ta.append("\n Your CON is now "+constitution+"."); derive(); if (old != hp) ta.append("\n Your hit points are now "+hp+"."); if (constitution == 1) c_age.remove(s_CON); } else if (c_age.getSelectedItem().equals(s_DEX)) { dexterity--; derive(); ta.append("\n Your DEX is now "+dexterity +". Your base Dodge skill is now "+dodge+"%."); if (dexterity == 1) c_age.remove(s_DEX); } else if (c_age.getSelectedItem().equals(s_APP)) { appearance--; ta.append("\n Your APP is now "+appearance+"."); if (appearance == 1) c_age.remove(s_APP); } if (c_age.getItemCount() == 0) { c_age.add(s_NA); c_age.add(s_STR); c_age.add(s_CON); c_age.add(s_DEX); c_age.add(s_APP); c_age.setEnabled(false); l_age.setEnabled(false); } } } public void init() { ButtonsActionListener shared = new ButtonsActionListener(); rnd = new Random(); ta = new TextArea( "Minimal Call of Cthulhu Character Generation (Java 1.1)\n\n" +"For \"Call of Cthulhu\", 5th edition, Copyright (C) 1992 by Chaosium Inc.\nAll rights reserved.\n\n" +"This program written by Jim W. Lai; additional Copyright (C) 1997.\n\n" +"Call of Cthulhu is a registered trademark of Chaosium, Inc." ,rows,cols,TextArea.SCROLLBARS_VERTICAL_ONLY); add("Center",ta); ta.setFont(new Font("Courier",Font.PLAIN,12)); ta.setEditable(false); Panel p = new Panel(); p.add(new Label("Investigator Era:")); c_era = new Choice(); c_era.add("1890s"); c_era.add("1920s"); c_era.add("1990s"); c_era.select(1); p.add(c_era); add("South",p); b_generate = new Button(s_generate); b_generate.addActionListener(shared); add("South",b_generate); b_school = new Button(s_school); b_school.addActionListener(shared); b_school.setEnabled(false); add("South",b_school); p = new Panel(); p.add(l_age = new Label("Preferred Aging Loss:")); c_age = new Choice(); c_age.add(s_NA); c_age.add(s_STR); c_age.add(s_CON); c_age.add(s_DEX); c_age.add(s_APP); c_age.setEnabled(false); l_age.setEnabled(false); p.add(c_age); add("South",p); b_age = new Button(s_age); b_age.setEnabled(false); b_age.addActionListener(shared); add("South",b_age); b_summary = new Button(s_summary); b_summary.setEnabled(false); b_summary.addActionListener(shared); add("South",b_summary); setSize(getPreferredSize()); } public class ButtonsActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if (cmd.equals(s_generate)) { c_age.setEnabled(false); l_age.setEnabled(false); String selection = c_era.getSelectedItem(); era = 1920; if (selection.equals("1890s")) { era = 1890; } else if (selection.equals("1990s")) { era = 1990; } generate(); summarize(); b_summary.setEnabled(true); b_school.setEnabled(true); c_age.removeAll(); c_age.add(s_NA); c_age.add(s_STR); c_age.add(s_CON); c_age.add(s_DEX); c_age.add(s_APP); c_age.setEnabled(false); l_age.setEnabled(false); b_age.setEnabled(true); return; } if (cmd.equals(s_school)) { b_school.setEnabled(false); school(); return; } if (cmd.equals(s_age)) { boolean enable = true; b_age.setEnabled(false); age10(); if (age <= 40 && age > 30) { c_age.remove(s_NA); c_age.setEnabled(true); l_age.setEnabled(true); doLayout(); } if (age <= 30 || c_age.getItemCount() > 0 && c_age.getItem(0).equals(s_NA) == false) { b_age.setEnabled(true); } if (c_age.getItemCount() > 0 && c_age.getItem(0).equals(s_NA) == false) { if (c_age.getSelectedItem() == null) c_age.select(0); } return; } if (cmd.equals(s_summary)) { summarize(); return; } } } private static WindowAdapter BetterWindowAdapter() { return new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; } public Dimension getPreferredSize() { return new Dimension(640,480); } public static void main(String args[]) { Frame f = new Frame("Call of Cthulhu Character Generator 1.1"); CoCchar app = new CoCchar(); app.init(); f.add("Center",app); f.pack(); f.show(); f.addWindowListener(BetterWindowAdapter()); app.start(); } }